【发布时间】:2015-09-11 17:41:41
【问题描述】:
printf 系列函数提供了一系列长度修饰符,其中两个是hh(表示signed char 或unsigned char 参数提升为int)和h(表示@987654328 @ 或 unsigned short 参数提升为 int)。从历史上看,这些长度修饰符仅被引入以创建与 scanf 的长度修饰符的对称性,并且很少用于 printf。
这是 ISO 9899:2011 §7.21.6.1 “fprintf 函数”¶7 的节选:
7 长度修饰符及其含义为:
hh指定以下d、i、o、u、x或X转换说明符适用于signed char或unsigned char参数(参数将根据整数提升进行提升,但在打印前将其值转换为signed char或unsigned char);或者后面的n转换说明符适用于指向有符号字符的指针 论据。
h指定以下d、i、o、u、x或X转换说明符适用于short int或@98765435 (参数将根据整数提升进行提升,但其值在打印前需要转换为short int或unsigned short int);或者后面的n转换说明符适用于指向短int参数的指针。...
忽略n 转换说明符的情况,这些几乎相同的段落对h 和hh 的行为有何看法?
- 在this answer 中,据称传递了超出
signed char、signed short、unsigned char或unsigned short范围的参数。对于带有h或hh长度修饰符的转换规范。是 未定义的行为, 因为参数不是从char、short等类型转换而来的。之前。 - 我声称对于
int类型的每个值,该函数以明确定义的方式运行,并且printf的行为就像参数被转换为char、short等。转换前。 - 也可以声称在默认参数提升之前使用不属于相应类型的参数调用函数是未定义的行为,但这似乎很深奥。
§7.21.6.1¶7(如果有的话)的这三种解释中哪一种是正确的?
【问题讨论】:
-
我提出了第一个要求(请参阅链接答案)。实际上,我确实认为,如果我们对段落中使用的词语持迂腐态度,我的主张就成立了(提升前的论点是
short变体),但本段/C 的精神使得FUZxxl的主张可能更有可能。 -
我认为第一种方法是正确的。转换例程很可能期望有限的范围,因此使用优化版本(想想 8 位或 16 位 CPU)。不确定,如果输入参数必须是相同的类型。问题是,格式字符串解析器如何从
short/etc 中分辨出“真实”int输入参数。转换为int。另一个方面可能是编译器的内联。在最坏的情况下,它可能会抑制优化,但不会影响其他任何事情,因为它的行为必须相同。 -
这条线有点不清楚 -
%h......but its value shall be converted to short int or unsigned short int before printing)。那么这是否意味着它在进行整数提升时可以保持大于unsigned short int /short int的值?如果是这样,它持有的值是否会转换回其原始变量类型?它的结果是什么? -
如果你传递一个 64 位整数,而我们
%hhd,那么你会受到伤害,因为这将占用 8 个字节,而printf预计它会占用 4 个(Windows 和Linux x86 反正) -
@Ben 当然是的。我应该更清楚地说明我在谈论
signed或unsigned int参数,因为由于默认参数提升,这些是h和hh预期的类型。
标签: c printf language-lawyer undefined-behavior short