Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

unsigned becomes signed in if-statement comparisons?

I have searched this site for an answer and found many responses to unsigned/signed comparison but this problem is that only unsigned parameters are compared but still it works funny.

The problem with the following code is that the first if-statment does not happen ("hello") where as the second ("world") does. This I have interpreted as the calculation that is done inside the if-statment generates a negative number but the exact same calculation done with the result saved to a variables does not (even though the result is being saved to a signed variable).

The compiler used is gcc 4.4.

unsigned short u16_varHigh;  
unsigned short u16_varLow;  
unsigned short u16_Res1;  
signed short   s16_Res1;  

u16_varHigh = 0xFFFF;  
u16_varLow = 10;

u16_Res1 = u16_varLow - u16_varHigh; // response is 11 as expected  
s16_Res1 = u16_varLow - u16_varHigh; // response is 11 as expected

// Does not enter  
if( (u16_varLow - u16_varHigh) > (unsigned short)5 )  
{  
 printf( "hello" );  
}

// Does enter  
if( (unsigned short)(u16_varLow - u16_varHigh) > 5 )  
{  
 printf( "world" );  
}

Can anyone explain this for me and perhaps come up with a solution for a fix so that the first if-statement works as well?

like image 896
Wilmer Avatar asked Nov 17 '10 12:11

Wilmer


2 Answers

In the expression:

if( (u16_varLow - u16_varHigh) > (unsigned short)5 )  

(u16_varLow - u16_varHigh) will be promoted to an int and evaluate to -65525. The fix for your problem is to cast to an unsigned type, like you do in the "Does enter"-code.

The reason s16_Res1 = u16_varLow - u16_varHigh; yields 11 is that the result of the subtraction, -65525, doesn't fit in a short.

like image 122
Andreas Brinck Avatar answered Nov 08 '22 22:11

Andreas Brinck


In the other answers we have seen that

u16_varLow - u16_varHigh

for you (with 16 bit short and 32 bit int) is equivalent to

(int)u16_varLow - (int)u16_varHigh

and thus its result is the int value -65525. Thus the assignment

s16_Res1 = u16_varLow - u16_varHigh; 

is equivalent to

s16_Res1 = -65525;

which in your case of 16 bit short yields "undefined behavior". You are just unlucky that your compiler decides to assign 11, instead. (Unlucky because I think that it is better to fail early.)

In contrast to that

u16_Res1 = -65525; 

is a valid assignment since u16_Res1 is of an unsigned type and arithmetic of unsigned types is modulo the appropriate power of two.

like image 21
Jens Gustedt Avatar answered Nov 08 '22 22:11

Jens Gustedt