Signed/unsigned mismatch compare

3
#include <stdio.h>
int main()
{
    int a = -2;         // 0xFFFFFFFE
    unsigned int b = 1; // 0x00000001

    if ((int)a > (int)b) printf("(int)a > (int)b;\n");
    else printf("(int)a < (int)b;\n");

    if ((unsigned int)a > (unsigned int)b) printf("(unsigned int)a > (unsigned int)b;\n");
    else printf("(unsigned int)a < (unsigned int)b;\n");

    if (a > b) printf("a > b;\n");
    else printf("a < b;\n");

    char c = -2;         // 0xFE
    unsigned char d = 1; // 0x01

    if ((char)c > (char)b) printf("(char)c > (char)d;\n");
    else printf("(char)c < (char)d;\n");

    if ((unsigned char)c > (unsigned char)d) printf("(unsigned char)c > (unsigned char)d;\n");
    else printf("(unsigned char)c < (unsigned char)d;\n");

    if (c > d) printf("c > d;\n");
    else printf("c < d;\n");

    return 0;
}


run result is:
(int)a < (int)b;
(unsigned int)a > (unsigned int)b;
a > b;
(char)c < (char)d;
(unsigned char)c > (unsigned char)d;
c < d;

Why a>b and c<d? And what is the default compiler ruler for this? I original think the compiler will convert all number to int type, but this is confused me.

c
unsigned
signed
asked on Stack Overflow Sep 18, 2020 by kpld • edited Sep 18, 2020 by rici

3 Answers

3

Why a>b

When two types (after the usual promotions to int/unsigned as needed) of the same rank yet differ in sign-ness, the signed type is converted to the unsigned type.

int a = -2;
unsigned int b = 1;
if (a > b)
if ((unsigned)a > b)   // convert int to unsigned
if ((unsigned)-1 > 2)  // convert int to unsigned
if (UINT_MAX > 2)

Why c<d

Usual promotions to int/unsigned given char is a signed char.

char c = -2;        
unsigned char d = 1;
if ((int)c > (int)d)  // promote char to int
if ((int)-2 > (int)1)
if (-2 > 1)

Had char been an unsigned char

char c = -2; // c takes on the value of CHAR_MAX + 1 - 2 (254)
char c = 254;        
unsigned char d = 1;
if ((int)c > (int)d)  // promote char to int
if ((int)254 > (int)1)
if (254 > 1)
1

This follows from the C rules for the Usual arithmetic conversions.

relational operators <, >, <=, >=, ==, !=
...
4) Otherwise, both operands are integers. Both operands undergo integer promotions (see below); then, after integer promotion, one of the following cases applies: If the types are the same, that type is the common type.

Otherwise (the types are not the same): If the types have the same signedness (both signed or both unsigned), the operand whose type has the lesser conversion rank (see below) is implicitly converted to the other type.

Otherwise (the signedness is different): If the unsigned type has conversion rank greater than or equal to the rank of the signed type, then the operand with the signed type is implicitly converted to the unsigned type.

Otherwise (the signedness is different, and the unsigned type has conversion rank less than the signed type): If the signed type can represent all values of the unsigned type, then the operand with the unsigned type is implicitly converted to the signed type.

Otherwise: Both operands undergo implicit conversion to the unsigned type counterpart of the signed operand's type.

The case a > b, for example, is highlighted above: the operands have the same int type, but different signedness. An int does not cover the entire range of unsigned int values (in the usual implementations, presumably including OP's), so the unsigned type has higher conversion rank than int and the comparison is done as (unsigned)a > b. The other cases follow from the same rules.

answered on Stack Overflow Sep 18, 2020 by dxiv • edited Sep 18, 2020 by dxiv
0

Because of "usual arithmetic conversions", the signed int will be converted into an unsigned int before being compared.

More on "usual arithmetic conversions": C in a Nutshell

Otherwise, one operand has a signed type T whose conversion rank is higher than that of the other operand’s type. The other operand is converted to type T only if type T is capable of representing all values of its previous type. If not, then both operands are converted to the unsigned type that corresponds to the signed type T.

The following lines of code contain some examples:

int i = -1;
unsigned int limit = 200U;
long n = 30L;

if ( i < limit )
  x = limit * n;

In this example, to evaluate the comparison in the if condition, the value of i, −1, must first be converted to the type unsigned int. The result is a large positive number. On a 32-bit system, that number is 2^32 − 1, and on any system it is greater than limit. Hence, the if condition is false.

answered on Stack Overflow Sep 18, 2020 by Chris Happy • edited Sep 18, 2020 by Chris Happy

User contributions licensed under CC BY-SA 3.0