C/C++ Arena

Step 5 of 8

The signed/unsigned comparison trap

When an expression mixes a signed and an unsigned integer of the same (or larger) size, C converts the signed one to unsigned before operating. For comparisons this produces results that look impossible:

#include <stdio.h>
#include <string.h>

int main(void) {
    int n = -1;
    size_t len = strlen("abc");
    printf("%d\n", len > (size_t)n);
    printf("%d\n", n < 0 || len > (size_t)n);
    unsigned int u = 1;
    printf("%d\n", -1 < (int)u);
    return 0;
}
0
1
1

The first line asks "is 3 greater than -1?" and gets false, because -1 converted to size_t is the largest possible value. (The example writes the conversion out as (size_t)n so it compiles without warnings, but plain len > n does exactly the same conversion behind your back.) The second line handles the negative case first, before any conversion happens, and gets the right answer. The third converts the unsigned side to int instead, which is safe here because 1 fits.

Small types are promoted first

Before doing arithmetic, C converts char and short (signed or unsigned) to int. These integer promotions mean small types don't overflow in the middle of an expression:

#include <stdio.h>

int main(void) {
    unsigned char a = 200, b = 100;
    int sum = a + b;                  /* both promoted to int: 300 */
    unsigned char wrapped = a + b;    /* 300 doesn't fit in 1 byte: stored as 300 - 256 = 44 */
    printf("%d %d\n", sum, wrapped);
    return 0;
}
300 44

The addition happens in int. Only storing the result in the 1-byte wrapped loses information, and since that's a conversion to an unsigned type it wraps around, which is well defined. Promotion is also why printf("%d", c) works for a char: it arrives as an int.

Where this bites

strlen, sizeof and container sizes are all unsigned (size_t). Comparing them with an int that might be negative, or subtracting two sizes (a_len - b_len is huge, not negative, when b is longer), are classic bugs.

Fixes

Your turn: longer_than(s, n) should return 1 when s has more than n characters. It's wrong for negative n (every string is longer than -1 characters). Fix it without casting the length to int (strings can be longer than INT_MAX).

Previous: Fixed-width types Next: Floating-point rounding