如果 char c = 0x80,为什么 printf("%d\n", c << 1) 输出 -256?
#include<stdio.h>
int main(void)
{
char c = 0x80;
printf("%d\n", c << 1);
return 0;
}
在本例中,输出为 -256
。如果我写 c << 0
则输出为 -128
。
我不明白这段代码背后的逻辑。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
char
可能在您的平台上进行签名,在这种情况下,0x80
代表 -128(假设二进制补码)。当
char
用作<<
运算符的操作数时,它会被提升为int
(仍然是 -128)。所以当你应用左移时,你会得到-256。从技术上讲,改变负值是实现定义未定义的,但您看到的是典型行为。char
may be signed on your platform, in which case0x80
represents -128 (assuming two's complement).When a
char
is used as an operand with the<<
operator, it is promoted toint
(still -128). So when you apply the left-shift, you get -256. Technically, shifting negative values isimplementation-definedundefined, but what you see is typical behaviour.您的出发点已经有问题了:
如果(在您的情况下似乎)
char
是有符号类型,则您将整数常量128
分配给仅保证的类型保留最大127
的值。然后,您的编译器可能会选择为您提供一些实现定义的值(我猜在您的情况下为 -128 )或发出范围错误。然后你就对该负值进行左移。这会产生未定义的行为。总的来说,您有几个实现定义的选择以及决定结果的未定义行为:
char
的符号性、128
转换为signed char
的选择char
的宽度int
的符号表示(存在三种可能性)int
上的左移>对您来说,查找所有这些案例并看看可能有什么不同的结果可能是一个很好的练习。
总之,一些建议:
Already your starting point is problematic:
If (as seemingly in your case)
char
is a signed type, you are assigning the integer constant128
to a type that is only guaranteed to hold values up to127
. Your compiler then may choose to give you some implementation defined value (-128
in your case I guess) or to issue a range error.Then you are doing a left shift on that negative value. This gives undefined behavior. In total you have several implementation defined choices plus undefined behavior that determine the outcome:
char
128
tosigned char
char
int
(there are three possibilities)int
It may be a good exercise for you to look up all these case an to see what the different outcomes may be.
In summary some recommendations:
char
c
被分配为0x80
。假设 8 位字节,其二进制表示值为10000000
。显然,在您的平台上,char
是一种签名类型。因此,0x80
(即10000000
)对应于-128。当
<<
应用于char
值时,它会提升为int
并保留符号。因此,当使用 32 位整数向左移动一次时,它会变成11111111111111111111111100000000
(二进制补码),即 -256。c
is assigned0x80
. Assuming 8-bit bytes, its value in binary representation, is10000000
. Apparently, on your platform,char
is a signed type. So,0x80
(i.e.10000000
) corresponds to -128.When
<<
is applied to achar
value, it is promoted toint
and the sign is preserved. So, when shifted once to the left, with 32-bit integers, it becomes11111111111111111111111100000000
(two's complement) which is -256.只是一个旁注。从自下而上的角度来看,按位移位(和掩码)基于体系结构的字长(以位表示)。单词的长度因建筑而异。
请参阅此 Wiki 页面了解不同架构
的字长 在目标体系结构中,可以使用位移来进行乘法和除法(在某些情况下),比使用操作数更快。
请参阅此 Wiki 页面,了解有趣的位移位图
依赖于体系结构,我们不能假设一段特定的位移代码在不同的体系结构中都会以相同的方式工作。然而,一旦熟悉了不同架构的不同字长的概念,位移就变得不那么神秘并且更可预测了。
值得庆幸的是,今天我们有 8 位、16 位、32 位和 64 位字长,并且只有 8 位字符长度。在古代计算时代,架构可能有 12 位、15 位或 23 位字长(等等,令人作呕)。
Just a side-note. From a bottom up perspective, bit-wise shifting (and masking) is based on an architecture's word-length (expressed in bits). The length of a word, varies from architecture to architecture.
See this Wiki page for word lengths by architecture
If one knows the word length of the target architecture, one can use bit-shifting to multiply, and divide (in some cases), faster than using operands.
See this Wiki page for interesting diagrams of bit-shifting
Since bit-shifted code is architecture dependent, one cannot assume a specific piece of bit-shifted code will work the same way from architecture to architecture. However, once one is familiar with the idea of different word lengths for different architectures, bit-shifting becomes less mysterious and more predictable.
Thankfully, today we have 8, 16, 32, and 64 bit word lengths, and exclusively 8 bit character lengths. In the days of ancient computing, an architecture might have a 12, or a 15, or a 23 bit word length (etc., ad nauseum).
我想知道为什么你的编译器不会抱怨 0x80 不适合 char 的警告,在你的平台上它只能表示从 -0x80 到 0x7F 的值。
尝试这段代码:
您的情况称为溢出。
I wonder why your compiler do not complain with a warning that 0x80 does not fit in char, which on your platform can represent only values from -0x80 to 0x7F.
Try this piece of code:
Your situation is called OVERFLOW.