Search code examples
ccharlanguage-lawyerc99

Why is SCHAR_MIN defined as -127 in C99?


§5.2.4.2.1 of C99 defines SCHAR_MIN as -127 and SCHAR_MAX as 127. Should not the range for an 8 bit signed integer be -128 to +127?

The limits.h for my compiler defines SCHAR_MIN as (-1 << ((CHAR_BIT)-1)), which is -128 given CHAR_BIT is 8.

Is there any reason why SCHAR_MIN was defined -127 and not -128 ?


Solution

  • It doesn't actually define SCHAR_MIN as -127, it defines the minimum range of signed characters to -127..127.

    It does this because it has to be able to handle the other two encoding schemes for signed numbers, those being ones' complement and sign/magnitude. Both of these have a positive and negative zero, stealing away the -128 you find in two's complement.

    ISO C (C99), section 6.2.6.2/2, states that an implementation must choose one of these three different representations for signed integral data types:

    • two's complement;
    • ones' complement; or
    • sign/magnitude

    The two's complement implementations far outweigh the others but the others do exist.

    In all those representations, positive numbers are identical, the only difference being the negative numbers.

    To get the negative representation for a positive number, you:

    • invert all bits then add one for two's complement.
    • invert all bits for ones' complement.
    • invert just the sign bit for sign/magnitude.

    You can see this in the table below, for both 5 and 0:

    number | two's complement    | ones' complement    | sign/magnitude
    =======|=====================|=====================|====================
         5 | 0000 0000 0000 0101 | 0000 0000 0000 0101 | 0000 0000 0000 0101
        -5 | 1111 1111 1111 1011 | 1111 1111 1111 1010 | 1000 0000 0000 0101
           |                     |                     |
         0 | 0000 0000 0000 0000 | 0000 0000 0000 0000 | 0000 0000 0000 0000
        -0 | 0000 0000 0000 0000 | 1111 1111 1111 1111 | 1000 0000 0000 0000
               (no difference)        (both of these have distinct +/-0)