我理解字符变量从(带符号)-128到127和(无符号)0到255
保持不变char x;
x = 128;
printf("%d\n", x);
但它是如何运作的?为什么我-128
获得x
?
答案 0 :(得分:3)
printf
是一个可变函数,仅为第一个参数提供精确类型
这意味着默认促销应用于以下参数,因此排名小于int
的所有整数都会提升为int
或unsigned int
,并且所有排名较小的浮动值{{1}被提升为double
。
如果您的实施具有double
为8,且简单CHAR_BIT
已签名并且您有一个强制性的2s补码实现,那么您就得到了
128(字面值)到-128(char
/ char
)到-128(signed char
)打印为int
=> -128
如果满足所有列出的条件但是必须完成2s补充实施,则会得到一个信号或一些实现定义的值。
否则输出为128,因为128适合int
/ char
。
案例2的标准报价(感谢Matt for unearthing the right reference):
6.3.1.3有符号和无符号整数
1当整数类型的值转换为_Bool以外的另一个整数类型时,if 该值可以用新类型表示,不变 2否则,如果新类型是无符号的,则通过重复添加或转换该值 减去一个可以在新类型中表示的最大值 直到该值在新类型的范围内.60)
3否则,新类型已签名且值无法在其中表示;无论是 结果是实现定义的或引发实现定义的信号。
答案 1 :(得分:1)
这一切都与可变参数函数,默认参数促销等无关。
假设您的系统已签名字符,则x = 128;
正在执行超出范围的分配。这种行为是实现定义的;这意味着编译器可以选择一个动作,但它必须记录它的作用(因此,可靠地执行)。允许此操作包括发出信号。
现代编译器为超出范围的赋值所做的通常行为是截断值的表示以适合目标类型。
在二进制表示中,128是000....00010000000
。
将其截断为带符号的char会给出二进制表示10000000
的签名字符。在所有现代C系统用于负数的two's complement representation中,这是值-128
的表示。 (对于历史的好奇心:在一个补码中,这是-127
,并且在符号幅度上,这是-0
,它可能是一个陷阱表示,因此会产生信号。)
最后,printf
准确地打印出此{char} -128
的值。由于默认参数提升以及%d
和char
的事实,INT_MIN <= CHAR_MIN
修饰符适用于INT_MAX >= CHAR_MAX
。这种行为是有保证的,除了在普通字符为无符号的系统上,sizeof(int)==1
(确实存在,但是如果你在其中,你就会知道它)。
答案 2 :(得分:0)
让我们在存储到8位时查看128
的二进制表示:
1000 0000
现在让我们在存储到8位时查看-128
的二进制表示:
1000 0000
当前设置的char
标准看起来是signed char
(请注意,这不是c标准中的内容,如果您不是here,请查看{{3}}相信我)因此,当您将128
的值分配给x
时,您需要为其分配值1000 0000
,因此当您编译并将其打印出来时,&{ #39; s打印出该二进制表示的有符号值(意思是-128
)。
事实证明,假设char
实际为signed char
,我的环境是相同的。正如预期的那样,如果我将x
转换为unsigned char
,那么我会获得128
的预期输出:
#include <stdio.h>
#include <stdlib.h>
int main() {
char x;
x = 128;
printf("%d %d\n", x, (unsigned char)x);
return 0;
}
给我-128 128
希望这有帮助!