在下面的示例中,打印了包含全1的字节的位表示:
#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无符号是合理的。有什么具体原因没有?
答案 0 :(得分:1)
这里的第一个问题是char
类型。永远不应该使用此类型来存储整数值,因为它具有实现定义的签名。这意味着它可以是有符号或无符号的,并且您将在不同的编译器上获得不同的结果。如果给定编译器上char
未签名,则此代码将按预期运行。
但是如果char
已签名,则char c = 255;
会产生一个太大的值。然后,值255将以某种特定于编译器的方式转换为带符号的数字。通常通过将原始数据值转换为二进制补码等价物。
像GCC这样的好编译器会给出一个警告:“隐式常量转换溢出”。
从不使用char
来存储整数来解决这个问题。请改用uint8_t
。
当您尝试将1 << 7
存储在给定编译器上签名的char
类型中时,会出现同样的问题。当发生这种情况时,z
将以负值(-128)结束。
在表达式z & c
中,两个操作数都以静默方式整数提升为类型int
。每当您使用小整数类型(例如char
)时,大多数C表达式都会发生这种情况。
&
运算符不关心操作数是否有符号,它将对变量的“原始数据”值执行按位AND运算。如果c
是已签名的char
并且原始值为0xFF
,那么您将获得一个结果为负数,并设置符号位。在两台补充计算机上的值-1
。
所以回答为什么你在两种情况下得到不同的结果:
当您将类型切换为int
时,值255
将适合c
,而不会转换为负值。 &
操作的结果也将是int
,此int
的符号位将永远不会设置,与char
情况下的情况不同。
执行-128 & 255
时,结果将为128
(0x80)。这是一个正整数。 z
是一个负整数,其值为-128
。它将被==运算符提升为int
,但符号会被保留。由于128不等于-128,因此MSB将打印为零。
如果您将char
切换为uint8_t
,则会得到相同的结果。
答案 1 :(得分:0)
(编辑澄清&#34;默认签名&#34; )
在第一个列表中,(z == c)
测试两个 char ;但是,在第二个列表中,(z == c)
测试一个 char 和一个 int 。
为了在 char 和 int 之间执行&
和==
操作,编译器会扩展 char 到 int 的大小。
关于第7位(第8位):
如果您的编译器默认情况下将 char 视为无符号,则条件为
(((int)(128) & (int)255) == (int)128)
将呈现 true ,并打印1
。但是在您的情况下,结果为false,并显示0
。
原因很可能是你的编译器认为 char 是签名的(默认情况下是gcc)。在这种情况下,设置为1 << 7
的 char 实际上是-128
,而在 int (至少两个字节)中,255是正数。< / p>
(char)-128
扩展为int (int)-128
,因此条件
if ((z & c) == z)
读取
if (((int)(-128) & (int)255) == (int)-128)
在这种情况下是假的。
答案 2 :(得分:0)
对于char到int,你必须将char定义为unsigned,因为默认情况下char或任何类型都被视为singed。
int main (void)
{
int c = 255;
unsigned char z;
int i;
for (i = 7; i >= 0; i--) {
z = 1 << i;
if ((z & c) == z) printf("1"); else printf("0");
}
printf("\n");
return 0;
}