我想将字符打印为正值:
char ch = 212;
printf("%u", ch);
但我得到:
4294967252
如何在输出中获取212
?
将你的ch
声明为
unsigned char ch = 212 ;
而且你的printf会正常工作。
这是因为在此情况下,您的系统上* char
类型被视为有符号类型。当发生这种情况时,在将数据传递给具有可变参数的函数时进行默认转换时,数据会进行符号扩展。由于212大于0x80,它被视为负数,%u
将该数字解释为一个大正数:
212 = 0xD4
当进行符号扩展时,FF
会被添加到您的数字前面,因此它变成:
0xFFFFFFD4 = 4294967252
这是要打印的数字。
请注意,此行为特定于您的实现。根据C99规范,所有char
类型都会被提升为(带符号的)int
,因为一个int
可以表示char
的所有值,有符号或无符号:
6.1.1.2:如果一个
int
能够表示原始类型的所有值,则该值将转换为int
;否则,它将转换为unsigned int
。
这导致将int
传递给格式指示器%u
,而该指示器期望的是unsigned int
。
为避免程序出现未定义行为,请添加显式类型转换,如下所示:
unsigned char ch = (unsigned char)212;
printf("%u", (unsigned int)ch);
char
的有无符号性质留给实现去决定,请参考这个问题以了解更多细节。char
作为参数时的整数提升,而后面的句子适用于早期操作,即使用int
初始化char
)。 - Eric Postpischilchar
会导致整数溢出,因此行为未定义。在许多C实现中,这会导致将212的二进制补码表示截断为八位,因此将比特解释为负值,因为设置了0x80比特,而不是因为初始值大于0x80(反例包括0x80和0x100)。 - Eric Postpischilchar
初始化之后,它被用作printf
的参数。执行整数提升,导致一个负的int
被传递给printf
。再次说明,许多C实现使用二进制补码,因此进行符号扩展,正如这个答案所说的那样。此时将值转换为unsigned
将产生一个大的正数。然而,这个答案没有解释实际行为是未定义的,因为一个int
被传递给了%u
的指定符,而%u
期望一个unsigned int
。 - Eric Postpischilunsigned
最大值,因此所有的char
值都可以适配于unsigned int
。 - Vilhelm Gray这段代码中有两个 bug。首先,在大多数带有有符号 char
的 C 实现中,char ch = 212
存在问题,因为 212 无法适应 8 位有符号 char
,且 C 标准没有完全定义其行为(它要求实现来定义行为)。正确的写法应该是:
unsigned char ch = 212;
其次,在 printf("%u",ch)
中,正常的 C 实现中,ch
将被提升为 int
。然而,%u
指定符期望一个无符号整数类型 unsigned int
,当传递错误类型时,C 标准没有定义行为。应改为:
printf("%hhu", ch);
(对于 %hhu
,printf
期望一个无符号字符,通常在 C 的实现中被提升为 int
。)
hh
修饰符。 - undefined如果由于某种原因您无法更改声明,则可以执行以下操作:
char ch = 212;
printf("%d", (unsigned char) ch);
char的范围是从127到-128。如果你赋值212,ch会存储-44(212-128-128),而不是212。因此,如果您尝试将负数打印为无符号数,则会得到(无符号int的最大值)-abs(number),在这种情况下为4294967252。
因此,如果您想将212存储为它本身,唯一能做的就是将ch声明为
unsigned char ch;
现在ch的范围是0到255。
char
默认是 signed
声明的,这意味着变量的范围是
-127 到 +127>
您的值已经溢出。要获取所需的值,您必须声明 unsigned
修饰符。修饰符 (unsigned
) 的范围是:
0 to 255
要获取任何数据类型的范围,请按照以下步骤进行:2^bit
示例:char
长度为8位,只需使用2 ^(power) 8
即可获得其范围。
char
默认情况下不是有符号的。标准规定(第6.2.5节,“类型”):“实现必须定义char
具有与signed char
或unsigned char
相同的范围、表示和行为”,并没有提到“默认”。char
是有符号还是无符号取决于实现的决定。 - phlummox
ch
改为unsigned char
,该代码的行为仍未被C标准定义。这是因为在正常的C实现中,unsigned char
会被提升为一个int
,因此printf
会接收到一个int
来匹配%u
格式指示符。然而,%u
需要一个unsigned int
,所以类型不匹配,C标准没有定义该行为。 - Eric Postpischilhh
长度修饰符的描述中也有具体说明:“参数将根据整数提升进行晋升,但在打印之前其值应转换为有符号字符或无符号字符。” - andypeaprintf()
时进行了明确的unsigned int
强制转换才起作用。添加-std=c11
到gcc-4.8.4
命令中以强制执行标准没有任何效果。 - ypxhh
的情况下,标准告诉我们,在提升之前的类型可能是signed char
或unsigned char
。这意味着ch
仍将被提升为int
,但转换%hhu
期望如此。然而,在printf(%u,ch)
中不存在hh
的情况下,这与本情况无关。 - Eric Postpischil