这是我的代码
#include<stdio.h>
void main()
{
char ch = 129;
printf("%d", ch);
}
我得到的输出为-127。这是什么意思?
答案 0 :(得分:4)
这意味着char
是一个8位变量,只能容纳2 ^ 8 = 256个值,因为声明是char ch
,ch
是signed
变量,这意味着它可以存储127个负值和正值。当你要求超过127时,该值从-128开始。
把它想象成一些街机游戏,你从屏幕的一边走到另一边:
ch = 50;
-----> 50 is stored
|___________________________________|___________| since it fits
-128 0 50 127 between -127
and 128
ch = 129;
--- 129 goes over
--> 127 by 2, so
|__|____________________________________________| it 'lands' in
-128 -127 0 127 -127
为了纪念Luchian Grigore,我们在这里发现了什么:
char
是一个容纳8位或一个字节的变量。所以我们有8 0和1并且努力代表你想要的任何价值。如果char
是signed
变量,则表示它是正数还是负数。你可能读到了代表符号的那一位,它是真实过程的抽象;事实上,它只是电子产品中首批实施的解决方案之一。但是这样一个简单的方法有一个问题,你将有两种方式来表示0(+0和-0):
0 0000000 -> +0 1 0000000 -> -0
^ ^
|_ sign bit 0: positive |_ sign bit 1: negative
保证不一致!!因此,一些非常聪明的人想出了一个名为Ones&#39;补语表示负数作为其正对应的否定(非操作):
01010101 -> +85
10101010 -> -85
这个系统......也有同样的问题。 0可以表示为00000000
(+0)和11111111
( - 0)。然后是一些聪明的人创造了Two's Complement,它将保留早期方法的否定部分然后加1,因此删除那个讨厌的-0并给我们一个闪亮的新数字到我们的范围:-128!。那么我们的范围现在如何?
00000000 +0
00000001 +1
00000010 +2
...
01111110 +126
01111111 +127
10000000 -128
10000001 -127
10000010 -126
...
11111110 -2
11111111 -1
所以,这应该让我们知道当我们的小处理器试图为变量添加数字时会发生什么:
0110010 50 01111111 127
+0000010 + 2 +00000010 + 2
------- -- -------- ---
0110100 52 10000001 -127
^ ^ ^
|_ 1 + 1 = 10 129 in bin _| |_ wait, what?!
是的,如果您查看上面的范围表,您可以看到最多127(01111111
)二进制文件很好,花花公子,没有什么奇怪的事情发生,但是在第8位设置为 - 128(10000000
)解释的数字不再保持其二进制大小,而是保持到2的补语表示。这意味着,二进制表示,变量中的位,1和0,以及我们心爱的char
的核心,确实持有129 ...它在那里,看看它!但是邪恶的处理器读到这一点-127导致变量HAD signed
破坏了它在1维欧几里德空间中通过实数线的臭味转移的所有正电位。
答案 1 :(得分:2)
这意味着您遇到了未定义的行为。
任何结果都是可能的。
char ch=129;
是UB,因为对于特定设置,129
不是char
的可表示值。
答案 2 :(得分:1)
在您的系统上:char 129与8位有符号整数-127具有相同的位。 无符号整数从0到255,有符号整数-128到127。
相关(C ++):
您可能也有兴趣阅读What is an unsigned char?
的最佳答案正如@jmquigley指出的那样。这是严格未定义的行为,您不应该依赖它。 Allowing signed integer overflows in C/C++
答案 3 :(得分:1)
您的char
很可能是使用Two's complement存储的8位有符号整数。这样的变量只能表示-128到127之间的数字。如果你做“127 + 1”,它会回绕到-128。所以129相当于-127。
答案 4 :(得分:1)
这是因为char
在一个字节上编码,因此8位数据。
实际上char
的值为7位,并且有一位用于符号,unsigned char
有8位数据用于其值。
这意味着:
将abcdefgh分别取为8位(a为最左边的位,h为最右边的位),该值用符号编码,bcdefgh用二进制格式编码为实数值:
42(十进制)= 101010(二进制) 存储为: ABCDEFGH 00101010
从内存中使用此值时: a为0:数字为正,bcdefgh = 0101010:值为42
当你输入129时会发生什么:
129(十进制)= 10000001(二进制) 存储为: ABCDEFGH 10000001
从内存中使用此值时: a为0:数字为负数,我们应该减去一个并反转该值中的所有位,所以(bcdefgh - 1)反转= 1111111:该值为127 数字是-127
答案 5 :(得分:0)
char
类型是一个8位有符号整数。如果您解释two's complement有符号表示中无符号字节129的表示,则得到-127。
答案 6 :(得分:0)
类型char
可以是signed
或unsigned
,这取决于编译器。大多数编译器都将其标记为“已签名”。
在您的情况下,编译器以静默方式将整数129转换为其带符号的变量,并将其放在一个8位字段中,从而产生-127。
答案 7 :(得分:0)
char
为8位,已签名。它只能保存-128到127的值。当您尝试为其分配129
时,您会得到您看到的结果,因为表示签名的位被翻转。想到它的另一种方式是数字“包裹”。
答案 8 :(得分:0)
普通char
是签名还是未签名,是实现定义的行为。这是C语言中一个非常愚蠢,模糊的规则。 int
,long
等保证会被签名,但char
可以签名或无符号,这取决于编译器的实现。
在您的特定编译器上,char
显然已签名。这意味着,假设您的系统使用两个补码,它可以保持-128到127的值。
您尝试将值129存储在此类变量中。这会导致未定义的行为,因为您会收到整数溢出。严格地说,当你这样做时,任何事情都可能发生。该程序可以打印“hello world”或开始拍摄无辜的旁观者,并且仍然符合ISO C.实际上,大多数(所有?)编译器将实现这种未定义的行为作为“环绕”,如其他答案所述。
总而言之,您的代码依赖于标准未明确定义的两种不同行为。了解这种不可预测的代码的结果如何以某种方式结束的价值有限。这里重要的是要认识到代码是模糊的,并学习如何以不模糊的方式编写代码。
例如,代码可以重写为:
unsigned char ch = 129;
甚至更好:
#include <stdint.h>
...
uint8_t ch = 129;
根据经验,请务必遵循MISRA-C:2004中的这些规则:
6.1普通的 char 类型只能用于存储和使用字符值。
6.2 签名和 unsigned char 类型仅用于存储和使用数值。