#include <stdio.h>
int main(void)
{
printf("%d", sizeof(signed int) > -1);
return 0;
}
结果为0(FALSE)。
怎么可能呢?我使用的是64位Ubuntu Linux,所以结果应该是(4>-1)=> 1 => True。
问题在于sizeof
操作符返回一个无符号数量(size_t
),因此比较会将-1
转换为无符号数,这使得它看起来像是一个非常大的数字。
你可以尝试这样做:
printf("%d", ((int)sizeof(signed int)) > -1);
signed int
的 sizeof
返回的是无符号类型 size_t
。当你比较一个带符号数和一个无符号数 [且无符号数的类型至少和带符号数的类型一样大] 时,在比较之前,带符号数会被转换为无符号数。这个转换使得 -1
变成了无符号类型的最大值。换句话说,就好像你写了:
#include <limits.h>
/* ... */
printf("%d", sizeof(signed int) > SIZE_MAX);
当你犯错时,可以让gcc发出警告,但默认情况下甚至不在-Wall
中: 你需要-Wextra
或更具体地说是-Wsign-compare
。(这个警告可能会产生很多误报,但我认为对于新代码打开它是有用的。)
(size_t)-1 == SIZE_MAX
。 - Alok SinghalC语言中有很多隐式转换,特别是理解所谓的“通常算术转换”非常有帮助,其中包括所谓的“整数提升”。1
实际规则有点复杂,但简化起来,当一个运算符具有不同类型的操作数时,所有标量类型都会自动转换。转换首先将较低级别的操作数转换为更高级别的类型。然后,如果只有一个操作数被标记为有符号,则它将被转换为无符号,除非带有符号类型的操作数更大并且可以表示所有无符号类型的值。在您的示例中并非如此,因为size_t几乎总是与int一样大或更大。
最后,在几乎所有机器上,-1的所有位都设置了,使其在作为无符号数时成为一个非常大的数字。
1. ISO/IEC 9899:1999 ("C99") 6.3 Conversions
sizeof
结果的类型是size_t
。所有合理的ABI都会使size_t
与unsigned long
具有相同的大小,这可能与unsigned int
的大小相同,也可能不同(它不能更小,但可能更大)。 - zwol