无符号整数和有符号字符的比较

4

我正在尝试将无符号整数与有符号字符进行比较,就像这样:

int main(){
  unsigned int x = 9;
  signed char y = -1;
  x < y ? printf("s") : printf("g");
  return 0;
}

我原本期望的输出是"g",但实际上却是"s"。这里进行了什么样的转换?

你尝试过使用调试器吗?变量 y 的值是多少? - Cody Gray
正在使用codepad.org进行编程。所以现在无法调试。 - badmaash
为什么-1 > sizeof(int)? - phuclv
可能是无符号和有符号整数的算术运算的重复问题。 - phuclv
4个回答

23

第6.3.1.8节:“通常算术转换”细节介绍了隐式整数转换。

如果两个操作数具有相同的类型,则不需要进行进一步转换。

这不适用于本例,因为它们是不同的类型。

否则,如果两个操作数都具有带符号整数类型或者两者都具有无符号整数类型,则具有较小整数转换等级的操作数将转换为具有更高等级的操作数的类型。

这不适用于本例,因为一个是有符号的,另一个是无符号的。

否则,如果具有无符号整数类型的操作数的等级大于或等于另一个操作数的类型的等级,则具有带符号整数类型的操作数将转换为具有无符号整数类型的操作数的类型。

Bingo。 x 等级比 y 高,因此将 y 提升为 unsigned int。这意味着它从 -1 变成了 UINT_MAX,远大于9。

其余规则不适用于本例,但我会出于完整性而包含它们:

否则,如果具有带符号整数类型的操作数的类型可以表示无符号整数类型的所有值,则具有无符号整数类型的操作数将转换为具有带符号整数类型的操作数的类型。

否则,两个操作数都将转换为与具有带符号整数类型的操作数的类型相对应的无符号整数类型。


本问题相关的等级如下所示。 所有等级均在C99第6.3.1.1节“布尔值、字符和整数”中详细说明,因此您可以参考该部分以获取更多详细信息。

long long int 的等级应大于 long int 的等级,

long long int的等级应该大于intint的等级应该大于short intshort int的等级应该大于signed char

char的等级应该与signed charunsigned char的等级相同。


非常好的解释。我想补充一点,在这种情况下,最好总是进行类型转换。选择您希望进行比较的类型,并将两者都转换为该类型:(signed int)x < (signed int)y 将保证您最初期望的结果。 - Lee
4
实际上,我几乎从不使用无符号整数。如果int无法容纳足够大的值,我会切换到long,甚至是long long(需要时)。太多次了,我被拒绝变为负数的无符号整数咬伤,使我的许多循环成为无限循环,导致痛苦和大量的抱怨 :-) - paxdiablo
3
@paxdiablo,我只是做相反的事情,并且从不尝试使用有符号整数类型。用于寻址、大小和类似内容的正确类型是size_t,它是无符号的。大多数情况下,这种类型完全捕捉了我从整数类型所需的语义。对于人们正在处理的任务,int 几乎总是错误的类型。对我而言有意义的带符号类型是 ptrdiff_t,但仅此而已。 - Jens Gustedt
2
不查阅资料,我认为整数提升是在算术转换之前应用的。所以你说的一切都是正确的,但请注意,就算术转换而言,右操作数在它们看到它时已经具有 int 类型。 - Steve Jessop

2

运行以下代码:

int main(){
  unsigned int x = 9;
  signed char y = -1;
  printf("%u\n", (unsigned int)y);
  x < (unsigned int)y ? printf("s") : printf("g");
  return 0;
}

输出结果为:
4294967295
s
经过强制类型转换后,y的值变得非常大。这就是为什么输出结果为s的原因。

2
我的猜测是,y被提升为unsigned int,变成了一个非常大的值(由于溢出)。因此条件得到满足。

1
如果你不知道,请不要回答。 - Jim Balter
@Jim Balter:我只是想给OP一个提示。如果你认为这不是正确的提示,可以自由地点个踩。 - Asha
如果要给提示,请在问题下面添加注释,而不是作为答案。提示和猜测不是答案。 - Jim Balter
谢谢您的建议。将在以后的评论/回答中注意这一点。 - Asha

1

字符被提升为无符号整数,其值为MAX_UINT,大于9。


如果它是一个无符号字符,那么有符号字符会被提升为无符号字符吗? - badmaash
@Abhi:是的。第3条款(请参见我的答案)仍然适用于“如果具有无符号整数类型的操作数的等级大于或等于...”。 - paxdiablo
1
@Abhi:不,只要你不在某些奇怪的实现中,其中sizeof(int)== sizeof(char),它们都将提升为“int”。 在这种情况下,两者都将成为“unsigned int”。因此,如果sizeof(int)> sizeof(char),则(unsigned char) 9 <(signed char) -1大致上是错误的,如果sizeof(int)== sizeof(char)则为真。 我说“大致”是因为重要的是范围而不是大小,但是假设int中没有填充位,它们对应。这很愚蠢,但通常在完全可移植的代码中不要使用小于“int”的类型进行算术运算(包括比较)。 - Steve Jessop

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