c++cunsignedsigned

Are types 'int' or 'long', 'char', etc. always signed in C and C++?


I always knew I had signed values when I used int or long, char, short, etc. in C and C++ development. By the way, depending on the compiler or OS, what happens when the default signedness of these types becomes unsigned? I'm inquiring because I've never seen a reference to this in a paper or a book, and I don't know it.


Solution

  • Types short, int, long and long long are all signed unless explicitly qualified as unsigned. Note that short and long are actually qualifiers themselves and the type int is implicit if omitted.

    Type char is special: it is different from type signed char, which obviously is signed and from type unsigned char, which is not. Depending on the platform and compiler settings, type char may be signed or unsigned. You can test this by comparing the value of the macro CHAR_MIN defined in <limits.h> to 0 or by casting -1 as (char) and testing if it stays negative.

    #include <limits.h>
    #include <stdio.h>
    
    int main(void) {
        if ((char)-1 < 0) {
            /* most common case */
            printf("char is signed, range is %d..%d\n", CHAR_MIN, CHAR_MAX);
        } else
        if (sizeof(char) == sizeof(int)) {
            /* corner case, for some DSP systems */
            /* char type is the same as unsigned int */
            printf("char is unsigned, range is %u..%u\n", CHAR_MIN, CHAR_MAX);
        } else {
            /* common case, enabled with -funsigned-char for gcc and clang */
            /* char values and constants will promote to int */
            printf("char is unsigned, range is %d..%d\n", CHAR_MIN, CHAR_MAX);
        }
        return 0;
    }
    

    Note that you cannot use the above tests for preprocessing, but the constants defined in <limits.h> can be used in preprocessor expressions:

    #include <limits.h>
    #include <stdio.h>
    
    int main(void) {
    #if CHAR_MIN < 0
        printf("char is signed, range is %d..%d\n", CHAR_MIN, CHAR_MAX);
    #elif CHAR_MAX == UINT_MAX
        printf("char is unsigned, range is %u..%u\n", CHAR_MIN, CHAR_MAX);
    #else
        printf("char is unsigned, range is %d..%d\n", CHAR_MIN, CHAR_MAX);
    #endif
        return 0;
    }
    

    This also works in C++, but there is a more idiomatic way to test it using std::is_signed_v<char>.