在C中打印时有符号和无符号字符的行为

在C中打印时有符号和无符号字符的行为,c,C,我在Windows7上编译了下面的C程序,代码是::Blocks 10.05 int main() { unsigned char a=-5; signed char b=-5; char c=-5; printf("%d %d %d \n",a,b,c); printf("%u %u %u \n",a,b,c); } 我期望得到以下输出 251 -5 -5 251 251 251 我是这样推理的, -5在2的补码表示法中表示为1111011。

我在Windows7上编译了下面的C程序,代码是::Blocks 10.05

int main()
{
    unsigned char a=-5;
    signed char b=-5;
    char c=-5;
    printf("%d  %d  %d \n",a,b,c);
    printf("%u  %u  %u \n",a,b,c);
}
我期望得到以下输出

251 -5 -5
251 251 251
我是这样推理的,

-5在2的补码表示法中表示为1111011。 因此,将打印251

但我得到了以下输出

251 -5 -5 
251 4294967291 4294967291
我知道4294967291是-5的32位2的补码表示


但是为什么无符号字符a被打印为251而不是4294967291?

printf
是一个可变函数,它会导致(由于@TheParamagneticCroissant的更正)积分参数被提升为int或无符号int。根据标准提升规则,它会对它们进行适当的符号扩展。这使得你得到的数字成为这次晋升过程后的结果

相反,您可以使用
“%”PRIu8
打印8位无符号数字,使用
“%”PRId8
打印8位有符号数字。但是请注意,参数仍将被提升,然后printf将根据格式说明符再次向下转换它们,这可能仍然会更改该值,但我无法从内存中确定这一点

此外,C中的字符不能保证为8位,最好包含
标题并使用适当的固定宽度类型

您的代码的固定版本如下:

#include <stdint.h>
int main()
{
    uint8_t a=-5;
    int8_t b=-5;
    printf("%" PRId8 "%" PRId8 "\n", a, b);
    printf("%" PRIu8 "%" PRIu8 "\n", a, b);
}
#包括
int main()
{
uint8_t a=-5;
int8_t b=-5;
printf(“%”PRId8“%”PRId8“\n”,a,b);
printf(“%“PRIu8”%“PRIu8”\n”,a,b);
}

注:我不包括字符的等价物,因为所有固定宽度类型都是定义的符号,因此没有直接等价于字符的未定义符号。

因为
a
持有值
251
,而不是值
-5

。Vality的回答稍有错误。因为
unsigned char
必须至少保存255个值,所以如果uint8\u t存在,
char\u BIT
必须为8

没有理由使用讨厌的
PRI
宏,只需使用以下命令:

unsigned char a = -5;
signed char b = -5;
char c = -5;

printf("%hhd  %hhd  %hhd \n", a, b, c);
printf("%hhu  %hhu  %hhu \n", a, b, c);

无符号
整数类型(包括
无符号字符
)使用模运算。对于
unsigned char
,即模
UCHAR\u MAX+1
,其中
UCHAR\u MAX
中实现定义的值,大多数实现为
255
255
也是标准允许的
UCHAR\u MAX
的最小值)。将
256
添加到
-5
(即获得
0
255
之间的余数,以便在代码中初始化
a
)将解释
a
的值为
251
的原因


至于为什么要打印任何值,当传递到
printf()
时,这些值被提升为
int
类型。此提升与格式字符串无关,但它是
%d
格式说明符所期望的,因此值会按您所看到的方式打印。

printf()
是可变的;它的参数被提升为
int
,如果它们比
int
窄,这是通常算术转换的一部分。请参阅,例如,您必须将格式说明符与类型匹配<代码>%d应用于所有字符类型。(还有其他说明符,但它们是不必要的)<代码>%u只能用于
无符号字符
(字符类型之外)。您的
%u
行会导致未定义的行为。这与非常类似,但我不确定它是否为重复。这两个问题的结果相似,但措辞却完全不同。如果投票人愿意提及我做错了什么,我将非常感激,因为我很累,身上没有C编译器,所以我只从内存中编码。“使用%u和%d格式说明符打印整数大小的有符号和无符号数字。这意味着您的字符将被提升为int和unsigned int“-否,它们将被提升,而不考虑格式说明符;它们被提升是因为
printf()
是可变的。它们也仅被提升为一种特定类型(根据
int
char
的大小和范围,它可以是
int
unsigned int
,在大多数现代机器上可能是
int
。)谢谢你修复它;我收回了我的DV。我还建议我们找一个重复的问题,我几乎完全肯定这个问题已经被问过好几次了。@ParamagneticCroissant你能不能看一下修复后的答案,我不想误导OP,即使修复后我也不能100%肯定我是对的。此外,我将我四处看看,看能不能找到一个dupeIm,我不太确定,我相信char可以更大(比如说12位),而uint8_不是另一个没有名字的离散类型。虽然我面前没有标准,所以不能肯定这是否是允许的,是否有任何系统可以做到。但是如果你这样做,我强烈建议你对字符位和错误进行显式检查。我同意你的观点lution可以在所有机器上工作,但最复杂的机器除外。@Vality没有一种类型可以小于
char
。但是我真的不在乎那些古老的系统,它们甚至不会有一个半新的libc。