如何解决printf()
在这种情况下,
#include <stdio.h>
int main()
{
unsigned char a = 1;
printf("%hhu",-a);
return 0;
}
-a
中的参数 printf
通过一元减运算符的整数提升提升为 int
,随后通过默认参数提升提升,最后转换为 unsigned char
通过格式说明符。
所以 -a
=> -(int)a
(by ~
) => 没有通过函数调用转换 => (unsigned char)-(int)a
(by %hhu
)。我的想法对吗?
解决方法
您是正确的,a
在 int
中被提升为 -a
,并且 printf("%hhu",-a);
将 int
传递给 printf
。使用 %hhu
执行的概念转换尚不清楚。
请注意,如果 a
不为零,则 -a
生成的值(在 int
中)不是 unsigned char
值。此外,对于八位 signed char
的二进制补码,如果 a
大于 128,则 -a
产生的值不是 signed char
值。
要理解 %hhu
,我们查看 C 2018 7.21.6.1 8 中 u
的规范:
unsigned int
参数被转换为无符号八进制 (o)、无符号十进制 (u)、...
对于 7.21.6.1 7 中的 hh
:
指定后面的 d、i、o、u、x 或 X 转换说明符适用于 signed char
或 unsigned char
参数(参数将根据整数提升而提升,但其值应在打印前转换为 signed char
或 unsigned char
);...
首先我们必须解决“signed char
或 unsigned char
”这个问题。这是否表示我们可以为 signed char
传递 unsigned char
或 %hhu
?我想不是;我认为作者刚刚将 %hhd
(旨在转换 signed char
)和 %hhu
(旨在转换 unsigned char
)的语言放在一起。所以我相信其意图是应该为 unsigned char
转换规范传递一个提升的 %hhu
。
Apple Clang 11.0.0 似乎同意,当传递 -a
(但不是 a
)时,它警告:“警告:格式指定类型 'unsigned char' 但参数类型为 'int' [-Wformat]”
如上所述,传递 -a
可能传递一个不能通过传递提升的 unsigned char
产生的值。它甚至可能传递一个不能通过传递提升的 signed char
或 unsigned char
产生的值。在这种情况下,可以说我们违反了传递 unsigned char
的要求,因此 C 标准没有指定结果行为。即使它说传递的值应转换为 unsigned char
,但我相信这是一种概念转换,而不是对库实现的特定要求,并且这也属于“好像”规则:它确实如果程序的最终定义行为相同,则实际上不必执行。但是,由于可能未定义传递不正确的值,因此我们没有定义的行为。
这可能是对规则的严格解读,但如果 printf
在 a
为 1 时打印“4294967295”而不是“255”,我不会感到惊讶。
printf
是一个可变参数函数。 ...
参数传递的参数类型在函数内部未知。因此,任何可变参数函数都必须依赖其他机制来解释 va_arg
的参数类型。 printf
和 family 使用 const char* format
字符串来“告诉他们”传递了什么样的参数。传递与其格式说明符指定的预期类型不同的类型会导致未定义行为。
例如:
printf("%f",24)
是未定义的行为。在任何地方都没有从 int
到 float
的转换,因为参数是按原样传递的(在提升之后),并且在 printf
内部,函数错误地将其第一个参数视为 float
. printf
不知道也不可能知道参数的实际类型是 int
。
可变参数会经历一些自己的提升。您感兴趣的问题 unsigned char
被提升为 int
或 unsigned int
(我不确定 tbo)。因此,可变参数实际上无法成为 unsigned char
类型。所以 hhu
while 确实是 unsigned char
的说明符,它实际上期望一个 unsigned int
(int
),这就是您传递给它的内容。
因此,由于一元减号和传递可变参数引起的两个整数提升,因此代码是安全的。不过,我不是 100% 确定。整数促销既奇怪又复杂。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。