#include<stdio.h>
int main(void)
{
char c = 0x80;
printf("%d\n", c << 1);
return 0;
}
-256
在这种情况下输出。如果我写c << 0
,那么输出是-128
.
我不明白这段代码背后的逻辑。
#include<stdio.h>
int main(void)
{
char c = 0x80;
printf("%d\n", c << 1);
return 0;
}
-256
在这种情况下输出。如果我写c << 0
,那么输出是-128
.
我不明白这段代码背后的逻辑。
char
可能在您的平台上签名,在这种情况下0x80
表示 -128(假设二进制补码)。
当 achar
与运算符一起用作操作数时<<
,它被提升为int
(仍为 -128)。因此,当您应用左移时,您会得到 -256。从技术上讲,转移负值是实现定义的未定义,但您看到的是典型行为。
您的出发点已经有问题:
char c = 0x80;
如果(在您的情况下似乎)char
是有符号类型,则您将整数常量分配给128
仅保证将值保存到127
. 然后,您的编译器可能会选择为您提供一些实现定义的值(-128
在您的情况下我猜)或发出范围错误。
然后你对该负值进行左移。这给出了未定义的行为。总的来说,您有几个实现定义的选择以及决定结果的未定义行为:
char
128
为signed char
char
int
(有三种可能)int
查看所有这些案例并了解不同的结果可能是一个很好的练习。
总结一些建议:
char
c
被分配0x80
。假设 8 位字节,其二进制表示的值为10000000
. 显然,在您的平台上,char
是签名类型。因此,0x80
(ie 10000000
) 对应于 -128。
当<<
应用于一个char
值时,它会被提升int
并保留符号。因此,当向左移动一次时,使用 32 位整数,它变为11111111111111111111111100000000
(二进制补码),即 -256。
只是一个旁注。从自下而上的角度来看,按位移位(和掩码)基于架构的字长(以位表示)。一个词的长度,因建筑而异。
如果知道目标体系结构的字长,则可以使用位移来进行乘法和除法(在某些情况下),比使用操作数更快。
由于位移代码依赖于体系结构,因此不能假设特定的位移代码在不同体系结构之间以相同的方式工作。然而,一旦人们熟悉了不同架构的不同字长的概念,移位就变得不那么神秘和更可预测了。
值得庆幸的是,今天我们有 8、16、32 和 64 位字长,并且只有 8 位字符长度。在古代计算时代,架构可能有 12 位、15 位或 23 位字长(等等,令人作呕)。
我想知道为什么您的编译器没有抱怨 0x80 不适合 char 的警告,在您的平台上它只能表示从 -0x80 到 0x7F 的值。
试试这段代码:
#include <stdio.h>
#include <limits.h>
#include <stdlib.h>
int main() {
printf("char can represent values from %d to %d.\n", CHAR_MIN, CHAR_MAX);
return EXIT_SUCCESS;
}
您的情况称为溢出。