我的电脑认为有符号整数比-1还要小?

3
#include <stdio.h>
int main(void)
{
    printf("%d", sizeof(signed int) > -1);
    return 0;
}

结果为0(FALSE)。

怎么可能呢?我使用的是64位Ubuntu Linux,所以结果应该是(4>-1)=> 1 => True。


据我所知,signed int和int的大小相同,都为4。Sizeof也取决于您使用的编译器,但您不应该遇到问题...嗯。 - Serguei Fedorov
1
“signed int”、“int”和“unsigned int”始终具有相同的大小,但该大小不一定为4。然而,sizeof结果的类型是size_t。所有合理的ABI都会使size_tunsigned long具有相同的大小,这可能与unsigned int的大小相同,也可能不同(它不能更小,但可能更大)。 - zwol
3个回答

10

问题在于sizeof操作符返回一个无符号数量(size_t),因此比较会将-1转换为无符号数,这使得它看起来像是一个非常大的数字。

你可以尝试这样做:

printf("%d", ((int)sizeof(signed int)) > -1);

8

signed intsizeof 返回的是无符号类型 size_t。当你比较一个带符号数和一个无符号数 [且无符号数的类型至少和带符号数的类型一样大] 时,在比较之前,带符号数会被转换为无符号数。这个转换使得 -1 变成了无符号类型的最大值。换句话说,就好像你写了:

#include <limits.h>
/* ... */
printf("%d", sizeof(signed int) > SIZE_MAX);

当你犯错时,可以让gcc发出警告,但默认情况下甚至不在-Wall中: 你需要-Wextra或更具体地说是-Wsign-compare。(这个警告可能会产生很多误报,但我认为对于新代码打开它是有用的。)


2
这与二进制补码无关。(size_t)-1 == SIZE_MAX - Alok Singhal
2
从技术上讲,即使一个操作数是无符号的,有符号类型也不总是被提升为无符号类型。参见6.3.1.8(1),只有在有符号类型不能表示所有可能值时,才会发生这种情况,而该无符号操作数可能更小。 - DigitalRoss
@DigitalRoss 完全正确,已更正。 - zwol
@Alok...我曾以为在补码或原码机器上,符号到无符号的转换理论上不会表现出相同的行为,但你是正确的。(C99 6.3.1.3p2) 不过这已经不重要了,考虑到已经很长时间没有制造出对于整数不是二进制补码的CPU了。 - zwol
@Zack,你说得对。我只是想挑剔一下。 - Alok Singhal

5

整数提升

C语言中有很多隐式转换,特别是理解所谓的“通常算术转换”非常有帮助,其中包括所谓的“整数提升”。1

实际规则有点复杂,但简化起来,当一个运算符具有不同类型的操作数时,所有标量类型都会自动转换。转换首先将较低级别的操作数转换为更高级别的类型。然后,如果只有一个操作数被标记为有符号,则它将被转换为无符号,除非带有符号类型的操作数更大并且可以表示所有无符号类型的值。在您的示例中并非如此,因为size_t几乎总是与int一样大或更大。

最后,在几乎所有机器上,-1的所有位都设置了,使其在作为无符号数时成为一个非常大的数字。


1. ISO/IEC 9899:1999 ("C99") 6.3 Conversions


促销(以及C语言中的所有转换)是转换,而不是重新解释表示。将-1转换为无符号类型始终是该类型中最大的值,与机器无关。 - R.. GitHub STOP HELPING ICE
从技术上讲,这是C99 6.3.1.3(2)的规定,但这与dmr和K&R的规定不同,恰好等同于重新解释二进制补码机器。人们不禁想知道一个奇怪的机器实际上会做什么。 - DigitalRoss
“变化”(从处理表示到值)发生在C语言首次标准化时,但我相信唯一的变化是在规范方式上,而不是行为。据我所知,在标准化之前从未有过非二补码C实现,允许非二补码的整个想法是委员会的无意义发明... - R.. GitHub STOP HELPING ICE

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接