5
\$\begingroup\$

Here's a bit tricky one, because AFAIK there is no existing platform, where conditionally compiled part of the code would actually get included by compiler, so it is entirely up to the human review to see if it is correct.

The purpose is to have abs function, which does not trigger undefined behavior with any user input, on any C99 standard compliant compiler, on any platform, and in the theoretical case of result not fitting in the return type, return maximum value that fits.

Apart from any bugs, blunders etc, the real challenge is to come up with a (maybe theoretical) platform where the code doesn't produce desired result, or (hopefully) be reasonably certain that it works in all cases allowed by the standard.

// function to review
#include <inttypes.h>
uintmax_t maxed_abs(intmax_t i) {
 if (i < 0) {
#if UINTMAX_MAX == INTMAX_MAX && INTMAX_MIN < -INTMAX_MAX
 // catch the theoretical case of 2's complement platform,
 // where unsigned and signed have same number of value bits
 if (i == INTMAX_MIN) return UINTMAX_MAX;
#endif
 return -(uintmax_t)i;
 }
 return (uintmax_t)i;
}
// test code
#include <stdio.h>
int main(void)
{
 printf("Enter int in range %jd .. %jd:\n > ", INTMAX_MIN, INTMAX_MAX);
 intmax_t i;
 if (scanf("%jd", &i) == 1) {
 printf("Result: |%jd| = %ju\n", i, maxed_abs(i));
 }
}
200_success
146k22 gold badges190 silver badges479 bronze badges
asked Feb 7, 2016 at 20:42
\$\endgroup\$
4
  • 1
    \$\begingroup\$ Taking the negative of an unsigned type like in -(uintmax_t)i invokes undefined behaviour though. Do you mean (uintmax_t) -i? \$\endgroup\$ Commented Feb 7, 2016 at 22:08
  • 1
    \$\begingroup\$ @DavidFoerster I don't think taking negative of unsigned invokes UB. All operations (except dovision by zero) are well defined for unsigned types. \$\endgroup\$ Commented Feb 8, 2016 at 7:17
  • 1
    \$\begingroup\$ Looks like you're right: stackoverflow.com/questions/8026694/…. I still believe that (uintmax_t) -i is more readable. \$\endgroup\$ Commented Feb 8, 2016 at 9:05
  • 1
    \$\begingroup\$ @DavidFoerster -i might cause signed integer overflow with value MAXINT_MIN. \$\endgroup\$ Commented Feb 8, 2016 at 15:41

1 Answer 1

3
\$\begingroup\$
  1. This kind of code relies on careful reading of the standard, so if it were me I would add cross-references to the sections of the standard that I was relying on, for example I might write:

    /* This relies on the following facts from the C99 standard:
     * 
     * §6.2.5.9 The range of nonnegative values of a signed integer
     * type is a subrange of the corresponding unsigned integer type.
     * It follows from this and §7.18.2.5 that UINTMAX_MAX >=
     * INTMAX_MAX.
     *
     * §6.2.6.2.2 Signed integers are represented as sign-and-
     * magnitude, two's complement, or one's complement. It follows
     * that INTMAX_MIN is either -INTMAX_MAX (in sign-and-magnitude or
     * one's complement) or -INTMAX_MAX-1 (in two's complement).
     */
    
  2. I don't like writing code that can't be tested on any platform that I have access to. Although the code looks good in this case, if you pursued this approach on a bigger scale, then it would be very surprising if all the untested code were correct. I would prefer to write something like:

    #if UINTMAX_MAX == INTMAX_MAX && INTMAX_MIN < -INTMAX_MAX
    #error "Two's complement with UINTMAX_MAX == INTMAX_MAX is not supported."
    #endif
    

    so that untested platforms get a compiler error instead of compiling and executing untested code. In the unlikely event that you discover such a platform, you can add the code and test it at that point.

answered May 10, 2016 at 10:16
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.