考虑以下示例:
#include <stdio.h>
int main(void)
{
unsigned char a = 15; /* one byte */
unsigned short b = 15; /* two bytes */
unsigned int c = 15; /* four bytes */
long x = -a; /* eight bytes */
printf("%ld\n", x);
x = -b;
printf("%ld\n", x);
x = -c;
printf("%ld\n", x);
return 0;
}
为了编译,我使用的是 GCC 4.4.7(它没有给我任何警告):
gcc -g -std=c99 -pedantic-errors -Wall -W check.c
我的结果是:
-15
-15
4294967281
问题是为什么 unsigned char
和 unsigned short
值都被正确“传播”到(signed)long
,而 unsigned int
不是吗?有没有这方面的引用或规则?
以下是 gdb
的结果(单词按小端顺序排列):
(gdb) x/2w &x
0x7fffffffe168: 11111111111111111111111111110001 11111111111111111111111111111111
(gdb) x/2w &x
0x7fffffffe168: 11111111111111111111111111110001 00000000000000000000000000000000
最佳答案
这是由于整数提升应用于操作数的方式以及一元减法的结果具有相同类型的要求。这在 6.5.3.3
一元算术运算符 部分中有所介绍,并说(强调我的前进):
The result of the unary - operator is the negative of its (promoted) operand. The integer promotions are performed on the operand, and the result has the promoted type.
和 c99 标准草案部分 6.3
Conversions 中涵盖的整数提升并说:
if an int can represent all values of the original type, the value is converted to an int; otherwise, it is converted to an unsigned int. These are called the integer promotions.48) All other types are unchanged by the integer promotions.
前两种情况,提升为int,结果为int。在 unsigned int 的情况下,不需要提升,但结果将需要转换回 unsigned int。
-15
使用 6.3.1.3
部分中规定的规则转换为 unsigned int 有符号和无符号整数 上面写着:
Otherwise, if the new type is unsigned, the value is converted by repeatedly adding or subtracting one more than the maximum value that can be represented in the new type until the value is in the range of the new type.49)
所以我们以 -15 + (UMAX + 1)
结束,这导致 UMAX - 14
导致一个大的无符号值。这就是为什么有时您会看到代码使用 -1
转换为无符号值以获得类型的最大无符号值,因为它最终总是 -1 + UMAX + 1
即 UMAX
。
关于c - 无符号类型和更大的有符号类型之间的隐式转换行为不一致,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23994293/