Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Comparison always fails with char and constant

I am trying to compare the first character of a string and a hex constant to determine the type of data. But every time it fails. Can anyone explain why below comparison always fails.

char charray[] = {0xAA, 0x00, 0x02};
char ch = charray[0];
if (0xAA == ch)
{
    printf("Equal\n");
}
like image 547
Nidhin MS Avatar asked Dec 22 '15 14:12

Nidhin MS


3 Answers

The problem is here:

char charray[] = {0xAA, 0x00, 0x02};

The char type has implementation-defined signedness, meaning that on some systems it will be equivalent to signed char. A signed char can only store values up to 0x7F and the MSB will get treated as a sign bit. This is what happens in your case, 0xAA gets converted to a signed value of -86 (it is implementation-defined what value it gets, I'm assuming two's complement).

The sign is then preserved in the expression 0xAA == ch, because ch is then promoted to type int and the sign is preserved. Meaning that you'll actually be comparing 0xAA == -86 which is false.

To avoid bugs like this, always use uint8_t when doing any form of arithmetic on byte level.

like image 82
Lundin Avatar answered Nov 18 '22 07:11

Lundin


if (0xAA == ch)

Assuming char is signed char (the behavior of char as signed char or unsigned char is implementation dependent in C), char is promoted to int in the == expression and in a 32-bit system you are actually comparing:

if (0xAA == 0xFFFFFFAA)

which is false.

One way to prevent the sign-extension is to cast the right operand to unsigned char:

if (0xAA == (unsigned char) ch)

But the best is simply to use unsigned char when you declare your array.

like image 31
ouah Avatar answered Nov 18 '22 06:11

ouah


0xAA is an int literal. char could be either signed or unsigned on your system. The C standard allows either.

In 0xAA == ch, the ch is promoted to an int type, and the comparison evaluates to 0.

like image 33
Bathsheba Avatar answered Nov 18 '22 06:11

Bathsheba