unsigned long 0 <-1?

我不懂这个!

#include  int main() { unsigned short t1 = 0, t2 = 0; if( t1 < t2-1 ) printf(" t1 < t2-1\n"); unsigned long s1 = 0, s2 = 0; if( s1 < s2-1 ) printf(" s1 < s2-1\n"); } 

这会导致:

  s1 < s2-1 

要么两者都失败,要么两者都失败。 我用gcc 4和4.2试过这个

C语言为许多操作员执行“常用算术转换” – 转换在C99标准的6.3.1.8中概述。 对于整体操作数,会执行首次促销,这就是造成问题的原因。 6.3.1.1(算术操作数/布尔值,字符和整数)概述了这些促销,其中包括:

如果int可以表示原始类型的所有值,则该值将转换为int; 否则,它将转换为unsigned int。 这些被称为整数促销。 整数促销不会更改所有其他类型。

促销仅应用于具有小于intunsigned int (或位域)的整数类型的对象或表达式。

所以在你的经历中:

 t1 < t2-1 

即使变量是unsigned short它们也会被提升为int,因为在你的平台上int可以表示unsigned short所有值。 因此,使用int类型计算表达式,并且不会发生下溢 - 表达式的t2-1部分最终为负1。

在表达式中:

 s1 < s2-1 

unsigned long类型不会被提升,因为它们具有比int / unsigned int更高的'rank',所以使用无符号算术(使用减法的下溢)来s2-1表达式,并且s2-1子表达式求值为非常数量多,不是负数1。

正如litb在评论中指出的那样,如果平台将int实现为16位类型(例如允许 - 例如MS-DOS),则unsigned short的提升将是unsigned int而不是int ,因为int wouldn' t能够表示unsigned short所有值( unsigned short必须至少为16位)。 在这种情况下,两个if语句都将评估为true。

我不确定,但我怀疑表达式t2-1自动扩展为int值。 我这里没有c标准确切的转换规则是什么,但我相信小于int的类型会自动加宽。

正如您所发现的那样,只要您在不同类型之间操作,C强制并不总是显而易见的。 t2是u16,1是int (大概是32位),所以t2-1正是这种“不同类型之间的操作”并导致对int的整体强制(因为它比u16 ……“更长”)。 之后,由于s2和1都是32位(虽然具有不同的符号),因此整体强制为无符号长。 因此,所涉及的类型的大小确实有助于确定整体强制的签名。

我建议避免使用混合签名(理想情况下也是混合大小!)操作(通过强制转换或特殊文字符号表示文字,例如1 ,否则将具有int类型并使您的生活变得复杂并且您的代码可能无法移植;-)。

-1表示为全1。 因此,当解释为无符号时,其值为2 ^ 32-1,这显然大于0.我猜第一个比较是扩展到执行32位有符号算术(可能是因为“1”是一个签名int)。

请注意,以下将转到printf,因为现在再次在16位无符号空间中进行比较:

 u32 temp = t2 - 1; if( t1 < temp ) printf(" t1 < t2-1\n");