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 x
和 unsigned 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"。
您可以通过使用带符号的转换说明符(d
或 i
)或无符号的转换说明符(o
、u
、[=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
) 并发现它需要将堆栈中接下来的两项解释为有符号整数。它分别引用 0xffffff96
和 00000096
作为堆栈上的值,并以十进制形式将两者呈现到控制台。
给定以下代码片段:
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 x
和 unsigned 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"。
您可以通过使用带符号的转换说明符(d
或 i
)或无符号的转换说明符(o
、u
、[=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
) 并发现它需要将堆栈中接下来的两项解释为有符号整数。它分别引用 0xffffff96
和 00000096
作为堆栈上的值,并以十进制形式将两者呈现到控制台。