printf如何知道变量是有符号的还是无符号的

How does printf knows if variable passed signed or unsigned

给定以下代码片段:

signed   char x = 150;
unsigned char y = 150;
printf("%d %d\n", x, y);

输出为:

-106 150

但是,我使用 same 格式说明符,用于在内存中以 same 方式表示的变量。 printf 如何知道它是有符号的还是无符号的。

两种情况下的内存表示是:

10010110

signed char x = 150; 导致实现定义行为,因为 150 不在 OP 的 signed char.

范围内

150 是 int,不在 signed char 范围内:

the new type is signed and the value cannot be represented in it; either the result is implementation-defined or an implementation-defined signal is raised. C17dr § 6.3.1.3 3

在这种情况下,x 的值为 150 - 256。

好的代码不会假设此结果为 -106,而是不会分配给范围外的 signed char 值。

然后...

通常,由于 通常的算法,signed char xunsigned char y 在作为参数传递给 ... 函数之前被提升为 int转换。 (int 范围内的类型提升为 int)。

因此printf("%d %d\n", x, y);不是问题。 printf() 收到 2 int 并且匹配 "%d" 说明符。

How does printf knows if variable passed signed or unsigned?

printf 函数没有 "know"。

您可以通过使用带符号的转换说明符(di)或无符号的转换说明符(ou、[=18)来有效地告诉它=] 或 X).

如果您将有符号整数打印为无符号整数,反之亦然,printf 将按照您的指示进行操作。


I used the same specifier "%d", and it printed different values (the positive one and the negative one"

在您的示例中,您正在打印有符号和无符号的 char 值。

signed   char x = 150;

x 中的值为 -106(8 位有符号),因为 150 大于 char 的最大值。 (对于您可能遇到的任何硬件/C 编译器,char 类型的范围是 -128 到 +127。)

unsigned char y = 150; 

y 中的值是预期的 150(8 位无符号)。

在通话地点。 char 值 -108 被符号扩展为更大的整数类型。 unsigned char 值 150 在没有符号扩展的情况下被转换。

调用 printf 时,传递给它的值具有不同的表示形式。

我们先来认识一下这个问题:

char x = 150;

x 从来没有值 150 开头。 150 将自动转换为 signed char。因此 x 将立即采用 -106 的值,因为 150 不能在带符号的 8 位值中表示。你还不如说:

char x = (signed char)150;  // same as -106, which is 0x96 in hex

其次,当作为变量参数传递时,char 和 short 值会自动提升为 int。作为被放入堆栈的一部分。这包括进行符号扩展。

因此,当您调用 printf("%d %d\n", x, y); 时,编译器会将其修改为:

 printf("%d %d\n", (int)x, (unsigned int)y);

以下内容被放入堆栈:

"%d %d\n"
0xffffff96   (int)x
0x00000096   (unsigned int)y

当 printf 运行时,它会解析堆栈中的格式化字符串 (%d %d\n) 并发现它需要将堆栈中接下来的两项解释为有符号整数。它分别引用 0xffffff9600000096 作为堆栈上的值,并以十进制形式将两者呈现到控制台。