当printf的相应参数不是short / char时,使用h或hh长度修饰符是不合法的吗?

printf系列提供了一系列长度修饰符,其中两个是hh (表示有signed charunsigned char参数提升为int )和h (表示有signed shortunsigned short参数,提升为int )。 从历史上看,这些长度修改器仅用于创建与scanf的长度修饰符对称,并且很少用于printf

以下是ISO 9899:2011§7.21.6.1“fprintf函数”¶7的摘录:

7长度修饰符及其含义是:

  • hh指定以下diouxX转换说明符适用于signed charunsigned char参数(该参数将根据整数提升进行提升,但其值应转换为signed char或打印前unsigned char ); 或者后面的n转换说明符适用于指向signed char参数的指针。

  • h指定以下diouxX转换说明符适用于short intunsigned short int参数(该参数将根据整数提升进行提升,但其值应转换为short int打印前的short intunsigned short int ); 或者后面的n转换说明符适用于指向short int参数的指针。

忽略n转换说明符的情况,这些几乎相同的段落对hhh的行为有何看法?

  • 在这个答案中 ,声称传递的参数超出了signed charsigned shortunsigned charunsigned short resp的范围。 对于具有hhh长度修饰符的转换规范。 是未定义的行为,因为参数未从charshort等类型转换。 之前。
  • 我声称该函数对于int类型的每个值都以明确定义的方式运行,并且printf行为就像参数转换为charshort等一样。 在转换之前。
  • 还可以声称在默认参数提升之前使用不属于相应类型的参数调用函数是未定义的行为,但这似乎是深奥的。

§7.21.6.1¶7(如果有的话)的这三种解释中的哪一种是正确的?

该标准规定:

如果任何参数不是相应转换规范的正确类型,则行为未定义。

[C2011 7.21.6.1/9]

“正确类型”的含义可以理解为可以解释,但对我来说最合理的解释是转换规范“适用于”的类型,如前面同一部分所述,部分引用这个问题。 我将关于参数提升的括号评论用于承认普通的参数传递规则,并避免将这些函数的任何含义视为特殊情况。 我不认为括号评论与确定论证的“正确类型”有关。

如果你传递一个类型比转换规范更正的参数,实际会发生什么是一个不同的问题。 我倾向于认为C系统不太可能由任何人实现,因为printf()参数实际上是一个char ,或者它是否是一个值在char范围内的char 。 但是,我断言,编译器检查参数类型与格式的对应关系是有效的行为,如果存在不匹配则拒绝程序(因为在这种情况下所需的行为是明确未定义的)。

另一方面,如果参数的值超出相应转换说明符隐含的范围,我当然可以想象实际行为不当的printf()实现(打印垃圾,损坏内存,吃午餐)。 由于行为未定义,这也是允许的。