我在计算机系统:程序员的角度,2 / E 一书中看到了以下代码。这很好用,并创建所需的输出。输出可以通过有符号和无符号表示的区别来解释。
#include<stdio.h>
int main() {
if (-1 < 0u) {
printf("-1 < 0u\n");
}
else {
printf("-1 >= 0u\n");
}
return 0;
}
上面的代码会产生-1 >= 0u
,但是,下面的代码与上面的代码相同,不会!换句话说,
#include <stdio.h>
int main() {
unsigned short u = 0u;
short x = -1;
if (x < u)
printf("-1 < 0u\n");
else
printf("-1 >= 0u\n");
return 0;
}
收益-1 < 0u
。为什么会这样?我无法解释这一点。
请注意,我见过类似this之类的问题,但它们没有帮助。
PS。正如@Abhineet所说,通过将short
更改为int
可以解决这一难题。但是,怎么能解释这种现象呢?换句话说,4个字节中的-1
为0xff ff ff ff
,而2个字节中的0xff ff
为unsigned
。将它们视为2s补码,将其解释为4294967295
,它们具有65535
和0
的对应值。它们都不低于-1 >= 0u
,我认为在这两种情况下,输出都需要x >= u
,即-1 < 0u
u =
00 00
x =
ff ff
。
小端英特尔系统上的示例输出:
简而言之:
-1 >= 0u
u =
00 00 00 00
x =
ff ff ff ff
对于int:
Appdelegate.m
答案 0 :(得分:10)
上面的代码产生-1&gt; = 0u
所有整数文字(数字常量)都有一个类型,因此也有一个签名。默认情况下,它们是int
类型的签名。附加u
后缀后,将文字转换为unsigned int
。
对于任何C表达式,其中有一个已签名的操作数和一个未被取消的操作数,balacing规则(正式:the usual arithmetic conversions)会隐式地将签名类型转换为无符号。
从有符号到无符号的转换是明确定义的(6.3.1.3):
否则,如果新类型是无符号的,则通过重复添加或转换该值 减去一个可以在新类型中表示的最大值 直到该值在新类型的范围内。
例如,对于标准二进制补码系统上的32位整数,无符号整数的最大值为2^32 - 1
(4294967295,limits.h中的UINT_MAX)。超过最大值的是2^32
。并-1 + 2^32 = 4294967295
,因此文字-1
将转换为值为4294967295
的无符号整数。哪个大于0。
但是,当您将类型切换为short时,最终会得到小整数类型。这是两个例子之间的区别。只要小整数类型是表达式的一部分,整数提升规则就会隐式将其转换为更大的int(6.3.1.1):
如果int可以表示原始类型的所有值(限制为 通过宽度,对于位字段),该值被转换为int; 否则,它将转换为unsigned int。这些被称为 整数促销。所有其他类型的整数不变 促销。
如果short
小于给定平台上的int
(就像在32位和64位系统上的情况一样),那么任何short
或unsigned short
都将始终获得转换为int
,因为它们可以放在一个内。
因此,对于表达式if (x < u)
,实际上最终会得到if((int)x < (int)u)
,其行为符合预期(-1小于0)。
答案 1 :(得分:3)
您正在使用C的整数提升规则。
类型小于int
的运算符会自动将其操作数提升为int
或unsigned int
。有关详细说明,请参阅注释。如果类型在此之后仍然不匹配(例如unsigned int与int),则二进制(双操作数)运算符还有一个步骤。我不会试图更详细地总结规则。 请参阅Lundin的回答。
This blog post更详细地介绍了这一点,并提供了与您类似的示例:signed和unsigned char。它引用了C99规范:
如果int可以表示原始类型的所有值,则值为 转换为int;否则,它将转换为unsigned int。 这些被称为整数促销。所有其他类型都保持不变 通过整数促销。
你可以更容易地在诸如godbolt之类的东西上玩这个,with a function that returns one or zero。只需查看编译器输出,看看最终会发生什么。
#define mytype short
int main() {
unsigned mytype u = 0u;
mytype x = -1;
return (x < u);
}
答案 2 :(得分:2)
除了你似乎假设的,这不是类型的特定宽度的属性,这里是2字节对4字节,而是要应用的规则的问题。整数提升规则规定short
和unsigned short
在相应值范围符合int
的所有平台上转换为int
。由于这是这种情况,因此将保留值并获取类型int
。 -1
在int
中完全可以表示0
。因此,-1
中的测试结果小于0
。
如果针对-1
对0u
进行测试,则公共转换选择unsigned
类型作为转换两者的公共类型。转换为-1
的{{1}}的值为unsigned
,大于UINT_MAX
。
这是一个很好的例子,为什么你永远不应该使用&#34; narrow&#34;算术或比较的类型。仅在具有服务器大小约束时才使用它们。对于简单变量,这种情况很少发生,但主要是对于大型数组,您可以通过窄类型存储获得真正的数据。
答案 3 :(得分:0)
0u
不是unsigned short
,而是unsigned int
。
编辑::对行为的解释, How comparison is performed ?
由Jens Gustedt回答,
这被称为&#34;通常的算术转换&#34;按标准和 只要两个不同的整数类型出现作为的操作数,就适用 同一个运营商。
本质上是做什么
如果类型有不同的宽度(更准确地说是标准 调用转换排名)然后如果两者都转换为更宽的类型 类型具有相同的宽度,除了非常奇怪的架构, unsigned of their wins签名为无符号转换值-1 任何类型总是会产生最高的可表示价值 无符号类型。
可以找到他撰写的更具说明性的博客here。