为什么打印 255
why is it printing 255
int main()
{
unsigned char a = -1;
printf("%d",a);
printf("%u",a);
}
当我执行了上面的程序后,我得到了 255 255 作为答案。
我们知道负数将存储在 2 的补码中。
因为它是 2 的补码,所以表示
1111 1111
-->2的补码。
但在上面我们正在打印 %d(int)
但整数是四个字节。
我的假设是,即使它是字符,我们也会强制编译器将其视为整数。
所以它在内部使用符号扩展概念。
1111 1111 1111 1111 1111 1111 1111 1111
.
根据上面的表示,在第一种情况下它必须是 -1,因为它是 %d(signed)。
在第二种情况下,它必须打印 (2^31- 1) 但它打印的是 255 和 255。
为什么在这两种情况下都打印 255。
告诉我我的假设是否错误并给我真正的解释。
unsigned char
从 0-255
运行所以负数 -1
将打印 255
-2
将打印 254
等等。 .
signed char
从 -128 to +127
运行,所以对于相同的 printf()
得到 -1,而 unsigned char
则不是这种情况
一旦您对 char 进行赋值,其余整数值将被填充,因此您对 2^31
的假设是错误的。
负数使用 2 的补码表示(取决于实现)
所以
1 = 0000 0001
所以为了得到 -1
我们做
----------------------------------------
2's complement = 1111 1111 = (255) |
-----------------------------------------
你的假设是错误的;字符将 "roll over" 到 255,然后填充到整数的大小。假设一个 32 位整数:
11111111
将被填充为:
00000000 00000000 00000000 11111111
编译器不知道 printf
中的额外参数应该 是什么类型,因为唯一指定它的东西应该被视为 4 字节int
为格式化字符串,编译时无关
幕后实际发生的事情是被调用者 (printf
) 收到指向每个参数的指针,然后转换为适当的类型。
与此大致相同的结果:
char a = -1;
int * p = (int*)&a; // BAD CAST
int numberToPrint = *p; // Accesses 3 extra bytes from somewhere on the stack
由于您可能 运行 在小端 CPU 上,因此 4 字节 int
0x12345678 在内存中的排列方式为 | 0x78 | 0x56 | 0x34 | 0x12 |
如果堆栈上a
之后的3个字节都是0x00
(它们可能是由于堆栈对齐,但不能保证),内存如下所示:
&a: | 0xFF |
(int*)&a: | 0xFF | 0x00 | 0x00 | 0x00 |
计算结果为 *(int*)&a == 0x000000FF
。
根据 a
的表述,您是正确的。但是,printf()
函数的 %d
和 %u
转换都将 int
作为参数。也就是说,你的代码和你写的一样
int main() {
unsigned char a = -1;
printf("%d", (int)a);
printf("%u", (int)a);
}
在您将 -1
分配给 a
的那一刻,您丢失了它曾经是有符号值的信息,a
的逻辑值为 255
.现在,当您将 unsigned char
转换为 int
时,编译器保留 a
的逻辑值并且代码打印 255
.
它正在打印 255,只是因为这是 ISO/IEC9899
的目的
H.2.2 Integer types
1 The signed C integer types int, long int, long long int, and the corresponding
unsigned types are compatible with LIA−1. If an implementation adds support for the
LIA−1 exceptional values ‘‘integer_overflow’’ and ‘‘undefined’’, then those types are
LIA−1 conformant types. C’s unsigned integer types are ‘‘modulo’’ in the LIA−1 sense
in that overflows or out-of-bounds results silently wrap. An implementation that defines
signed integer types as also being modulo need not detect integer overflow, in which case,
only integer divide-by-zero need be detected.
如果给出这个,打印 255 绝对是 LIA-1 所期望的。
否则,如果您的实现不支持 C99 的 LIA-1 附件部分,那么它只是未定义的行为。
int main()
{
unsigned char a = -1;
printf("%d",a);
printf("%u",a);
}
当我执行了上面的程序后,我得到了 255 255 作为答案。
我们知道负数将存储在 2 的补码中。
因为它是 2 的补码,所以表示
1111 1111
-->2的补码。
但在上面我们正在打印 %d(int)
但整数是四个字节。
我的假设是,即使它是字符,我们也会强制编译器将其视为整数。 所以它在内部使用符号扩展概念。
1111 1111 1111 1111 1111 1111 1111 1111
.
根据上面的表示,在第一种情况下它必须是 -1,因为它是 %d(signed)。 在第二种情况下,它必须打印 (2^31- 1) 但它打印的是 255 和 255。 为什么在这两种情况下都打印 255。 告诉我我的假设是否错误并给我真正的解释。
unsigned char
从 0-255
运行所以负数 -1
将打印 255
-2
将打印 254
等等。 .
signed char
从 -128 to +127
运行,所以对于相同的 printf()
得到 -1,而 unsigned char
一旦您对 char 进行赋值,其余整数值将被填充,因此您对 2^31
的假设是错误的。
负数使用 2 的补码表示(取决于实现)
所以
1 = 0000 0001
所以为了得到 -1
我们做
----------------------------------------
2's complement = 1111 1111 = (255) |
-----------------------------------------
你的假设是错误的;字符将 "roll over" 到 255,然后填充到整数的大小。假设一个 32 位整数:
11111111
将被填充为:
00000000 00000000 00000000 11111111
编译器不知道 printf
中的额外参数应该 是什么类型,因为唯一指定它的东西应该被视为 4 字节int
为格式化字符串,编译时无关
幕后实际发生的事情是被调用者 (printf
) 收到指向每个参数的指针,然后转换为适当的类型。
与此大致相同的结果:
char a = -1;
int * p = (int*)&a; // BAD CAST
int numberToPrint = *p; // Accesses 3 extra bytes from somewhere on the stack
由于您可能 运行 在小端 CPU 上,因此 4 字节 int
0x12345678 在内存中的排列方式为 | 0x78 | 0x56 | 0x34 | 0x12 |
如果堆栈上a
之后的3个字节都是0x00
(它们可能是由于堆栈对齐,但不能保证),内存如下所示:
&a: | 0xFF |
(int*)&a: | 0xFF | 0x00 | 0x00 | 0x00 |
计算结果为 *(int*)&a == 0x000000FF
。
根据 a
的表述,您是正确的。但是,printf()
函数的 %d
和 %u
转换都将 int
作为参数。也就是说,你的代码和你写的一样
int main() {
unsigned char a = -1;
printf("%d", (int)a);
printf("%u", (int)a);
}
在您将 -1
分配给 a
的那一刻,您丢失了它曾经是有符号值的信息,a
的逻辑值为 255
.现在,当您将 unsigned char
转换为 int
时,编译器保留 a
的逻辑值并且代码打印 255
.
它正在打印 255,只是因为这是 ISO/IEC9899
的目的H.2.2 Integer types
1 The signed C integer types int, long int, long long int, and the corresponding unsigned types are compatible with LIA−1. If an implementation adds support for the LIA−1 exceptional values ‘‘integer_overflow’’ and ‘‘undefined’’, then those types are LIA−1 conformant types. C’s unsigned integer types are ‘‘modulo’’ in the LIA−1 sense in that overflows or out-of-bounds results silently wrap. An implementation that defines signed integer types as also being modulo need not detect integer overflow, in which case, only integer divide-by-zero need be detected.
如果给出这个,打印 255 绝对是 LIA-1 所期望的。
否则,如果您的实现不支持 C99 的 LIA-1 附件部分,那么它只是未定义的行为。