在下面的示例中,打印了所有字节的位表示:
#include <stdio.h>
int main (void)
{
char c = 255;
char z;
for (int i = 7; i >= 0; i--) {
z = 1 << i;
if ((z & c) == z) printf("1"); else printf("0");
}
printf("\n");
return 0;
}
输出为11111111
现在我们把char c
改成int c
,这样例子就变成了:
#include <stdio.h>
int main (void)
{
int c = 255;
char z;
for (int i = 7; i >= 0; i--) {
z = 1 << i;
if ((z & c) == z) printf("1"); else printf("0");
}
printf("\n");
return 0;
}
现在输出是 01111111
。
为什么输出不同?
更新
编译以下test.c
:
#include <stdio.h>
int main(void)
{
char c=-1;
printf("%c",c);
return 0;
}
$ gcc test.c
$ ./a.out | od -b
0000000 377
0000001
输出是377,说明glibc与gcc矛盾,因为signed char会自动转成unsigned char。 为什么会有这样的并发症?默认情况下 char unsigned 是合理的。有什么具体原因吗?
最佳答案
这里的第一个问题是
char
类型。这种类型不应该用于存储整数值,因为它具有实现定义的符号。这意味着它可以是有符号的也可以是无符号的,你会在不同的编译器上得到不同的结果。如果char
在给定的编译器上未签名,那么此代码将按您预期的方式运行。但万一
char
已签名,char c = 255;
将导致一个太大的值。值 255 然后将以某种特定于编译器的方式转换为带符号的数字。通常通过将原始数据值转换为等效的二进制补码。GCC 等优秀的编译器会对此发出警告:“隐式常量转换溢出”。
通过从不使用
char
来解决此错误用于存储整数。使用uint8_t
反而。当您尝试存储
1 << 7
时出现同样的问题。在char
里面在您给定的编译器上签名的类型。z
发生这种情况时,最终会变成负值 (-128)。在表达式
z & c
中, 两个操作数都是默默地提升为类型int
的整数.每当您使用小整数类型(例如char
)时,大多数C 表达式都会发生这种情况。 .&
运算符不关心操作数是否有符号,它会对变量的“原始数据”值进行按位与运算。当c
是签名char
并具有原始值0xFF
,你会得到一个负的结果,并设置了符号位。值-1
在二进制补码计算机上。
所以要回答为什么在这两种情况下会得到不同的结果:
当您将类型切换为 int
时, 值 255
将适合内部 c
而不会转换为负值。 &
的结果操作也将是一个 int
和这个 int
的符号位永远不会被设置,不像在 char
中那样案例。
当你执行 -128 & 255
结果将是 128
(0x80)。这是一个正整数。 z
然而是一个负整数,值为 -128
.它将被提升为 int
通过 == 运算符,但符号被保留。由于 128 不等于 -128,因此 MSB 将打印为零。
如果切换 char
,您会得到相同的结果至 uint8_t
.
关于c - int如何转换为char,char如何转换为int?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40479358/