开发者

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.

开发者_Python百科
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?


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.


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.


In the "usual arithmetic conversions", types smaller than int are promoted to either int or unsigned int before they are used in most expressions. The rule is that if int can represent all the values of the smaller type, then it is promoted to int; otherwise it is promoted to unsigned int. This is often considered something of a wart, because in many cases it causes unsigned char and unsigned short values to be promoted to int.

This is exactly what you're seeing - u16_varLow and u16_varHigh and (unsigned short)5 are all promoted to int before the subtraction and comparison, which then happen using int. If you wish to be certain that an expression will use unsigned arithmetic, you must do it in unsigned int, not unsigned short:

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


The first one, if( (u16_varLow - u16_varHigh) > (unsigned short)5 ) will never pass, as (u16_varLow - u16_varHigh) returns negative number, because it's treated as an integer. The second one casts the same negative number, to unsigned short, that's why it passes.

Note - you know that all this is platform-dependent, right? The size of short, int, etc. depends on the concrete platform.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜