我在这个网站上搜索了一个答案,发现很多对未签名/签名比较的回复,但是这个问题是只比较了无符号参数,但它仍然很有趣。
以下代码的问题是第一个if
- 声明没有发生(“你好”),而第二个(“世界”)则发生。这个我已经解释为在if
内部进行的计算 - - statment生成一个负数但是保存到变量的结果完全相同的计算没有(即使结果被保存到一个有符号的变量)。
使用的编译器是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" );
}
任何人都可以为我解释一下这个问题,也许会想出一个解决方案来解决问题,以便第一个if
- 语句能够正常工作吗?
答案 0 :(得分:4)
在表达式中:
if( (u16_varLow - u16_varHigh) > (unsigned short)5 )
(u16_varLow - u16_varHigh)
将被提升为int
并评估为-65525。您的问题的修复方法是转换为无符号类型,就像在“输入”代码中一样。
s16_Res1 = u16_varLow - u16_varHigh;
得出11的原因是减法的结果-65525不适合短路。
答案 1 :(得分:2)
在其他答案中,我们已经看到了
u16_varLow - u16_varHigh
对你(16位short
和32位int
)相当于
(int)u16_varLow - (int)u16_varHigh
因此其结果是int
值-65525
。因此分配
s16_Res1 = u16_varLow - u16_varHigh;
相当于
s16_Res1 = -65525;
在你的16位short
的情况下产生“未定义的行为”。您只是不幸的是,您的编译器决定分配11
。 (不幸的是因为我认为最好早点失败。)
与此相反
u16_Res1 = -65525;
是一个有效的赋值,因为u16_Res1
是无符号类型,无符号类型的算术是以2的适当幂为模。
答案 2 :(得分:2)
在“通常的算术转换”中,小于int
的类型会在大多数表达式中使用之前提升为int
或unsigned int
。规则是,如果int
可以表示较小类型的所有值,则将其提升为int
;否则会被提升为unsigned int
。这通常被视为疣,因为在许多情况下,它会将unsigned char
和unsigned short
值提升为int
。
这正是您所看到的 - u16_varLow
和u16_varHigh
以及(unsigned short)5
在减法和比较之前都被提升为int
,然后使用{{int
1}}。如果您希望确定表达式将使用无符号算术,则必须在unsigned int
,不 unsigned short
中执行此操作:
if( ((unsigned)u16_varLow - (unsigned)u16_varHigh) > 5U )
答案 3 :(得分:1)
第一个,if( (u16_varLow - u16_varHigh) > (unsigned short)5 )
将永远不会通过,因为(u16_varLow - u16_varHigh)
返回负数,因为它被视为整数。第二个将相同的负数转换为无符号短,这就是它通过的原因。
注意 - 您知道这一切都取决于平台,对吗? short
,int
等的大小取决于具体平台。