Search code examples
cundefined-behaviorc89

Is converting from unsigned char to signed char and vice versa in C89 well defined?


Note: The suggested duplicate deals with unsigned int and signed int, not unsigned char and signed char. The suggested duplicate question deals with C11. This question is concerned with C89 only. Can this question be reopened?

My code:

#include <stdio.h>

int main()
{
    signed char c;
    unsigned char d;

    c = (signed char) -2;
    d = (unsigned char) c;
    printf("%d %d\n", c, d);

    d = (unsigned char) 254;
    c = (signed char) d;
    printf("%d %d\n", c, d);

    return 0;
}

Output:

$ clang -Wall -Wextra -pedantic -std=c89 foo.c && ./a.out
-2 254
-2 254

Is the output guaranteed to be -2 254 in a standard-conforming C89 compiler for both conversions shown above? Or is the output dependent on the implementation?


Solution

  • Is converting from unsigned char to signed char and vice versa in C89 well defined?

    Conversions to unsigned types is well defined. To signed types has implementation details.

    Is the output guaranteed to be -2 254 in a standard-conforming C89 compiler for both conversions shown above?

    No.

    Or is the output dependent on the implementation?

    Yes.


    Not all implementations use 8-bit char and conversions to signed types incur implementation details.

    Spec details: C89 Conversions. This wording differs from recent C specs. I have not found a significant difference.


    When UCHAR_MAX <= INT_MAX, code could use below and let the compiler emit optimized, well defined code.

    c = (signed char) (d > SCHAR_MAX ? d - UCHAR_MAX - 1 : d);
    

    Likely needs some more thought to cover all cases.