具有以下简单的C ++代码:
#include <stdio.h>
int main() {
char c1 = 130;
unsigned char c2 = 130;
printf("1: %+u\n", c1);
printf("2: %+u\n", c2);
printf("3: %+d\n", c1);
printf("4: %+d\n", c2);
...
return 0;
}
输出如下:
1: 4294967170
2: 130
3: -126
4: +130
有人可以向我解释第一行和第三行的结果吗?
我正在使用具有所有默认设置的Linux gcc
编译器。
答案 0 :(得分:1)
char
是8位。这意味着它可以表示2 ^ 8 = 256个唯一值。 uchar
代表0到255,带符号的char
代表-128到127(可以绝对代表任何东西,但这是典型的平台实现)。因此,为char
分配130超出2的范围,并且当该值解释为时,该值溢出并将值包装为-126。编译器将130视为整数,并进行从char
到int
的隐式转换。在大多数平台上,int是32位,符号位是MSB,值130很容易适合前8位,但随后编译器希望将24位切成小节以将其压缩为char。如果发生这种情况,并且您已经告诉编译器您想要一个带符号的char,则前8位的MSB实际上代表-128。哦哦!您现在在存储器char
中有此存储器,当将其解释为带符号的char时,它是-128 + 2。我在平台上的皮棉对此尖叫。 。
我将重点放在解释上,因为在内存中,两个值是相同的。您可以通过在1000 0010
语句中强制转换值printf
来确认这一点,然后再次看到130。
在第一个printf("3: %+d\n", (unsigned char)c1);
语句中看到较大值的原因是,您正在将有符号的printf
投射到无符号的char
,其中int
已经溢出。机器首先将char
解释为-126,然后强制转换为无符号char
,该数字不能表示该负值,因此可以得到有符号的{{ 1}}并减去126。
2 ^ 32-126 = 4294967170。 。宾果游戏
在int
语句2中,所有机器要做的就是添加24个零以达到32位,然后将该值解释为int
。在语句一中,您已经告诉您您有一个带符号的值,因此它将首先将其转换为32位-126值,然后将-ve整数解释为无符号整数。再次,它翻转了如何解释最高有效位。有2个步骤:
琐事的有趣之处在于,如果您执行printf
,则可以抑制叮当响的linter警告,但基于上述逻辑,您仍然会得到相同的垃圾(即,隐式转换会丢弃前24个位,而符号位无论如何都为零)。我已基于探索此问题(如果您确实想关注此问题,请发42137)提交了一份LLVM整洁的缺少功能报告
答案 1 :(得分:1)
(此答案假设您的计算机上char
的范围是-128至127,unsigned char
的范围是0至255,而unsigned int
的范围是0至4294967295,碰巧是这种情况。)
char c1 = 130;
此处,130在char
所代表的数字范围之外。 c1
的值是实现定义的。在您的情况下,数字恰好“环绕”,将c1
初始化为static_cast<char>(-126)
。
在
printf("1: %+u\n", c1);
c1
被提升为int
,从而产生-126
。然后,%u
说明符将其解释为unsigned int
。这是未定义的行为。这次生成的数字恰好是unsigned int
可以表示的唯一数字,与-126的4294967296模(即4294967170)一致。
在
printf("3: %+d\n", c1);
int
说明符将-126
值%d
直接解释为int
,并按预期(?)输出-126。
答案 2 :(得分:1)
在情况1、2中,格式说明符与参数的类型不匹配,因此程序的行为是不确定的(在大多数系统上)。在大多数系统上,char
和unsigned char
小于int
,因此当它们作为可变参数传递时,它们会提升为int。 int
与要求%u
的格式说明符unsigned int
不匹配。
在unsigned char
和int
一样大的异国系统(您的目标不是)上,它将升级为unsigned int
,在这种情况下,4将具有UB需要int
。
3的解释很大程度上取决于实现指定的细节。结果取决于char
是否签名,取决于可表示范围。
如果130是char
的可表示值,例如当它是无符号类型时,则130将是正确的输出。事实并非如此,因此我们可以假设char
是目标系统上的带符号类型。
使用无法代表的值(例如char
用130表示)初始化有符号整数会导致实现定义的值。
在带正负号的2的补码表示形式的系统上(这是当今普遍存在的表示形式),实现定义的值通常是可表示的值,与不可表示的值乘以可表示的值的数量。 -126与130模256一致,并且是char
的可表示值。