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

fuz*_*fuz 9 c printf short undefined-behavior language-lawyer

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

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

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

  • hh用于指定后续的d,i,o,u,x,或X转换说明适用于一个signed charunsigned char参数(该参数将被提升根据整数促销,但它的值应被转换成signed charunsigned char之前印刷); 或者以下n转换说明符适用于指向signed char参数的指针.

  • h用于指定后续的d,i,o,u,x,或X转换说明适用于一个short intunsigned short int参数(该参数将被提升根据整数促销,但它的值应被转换成short intunsigned short int之前印刷); 或者以下n转换说明符适用于指向short int参数的指针.

  • ...

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

  • 此答案,它被要求传递参数是一个的范围之外signed char,signed short,unsigned char,或unsigned shortRESP.对于带有hhh长度修饰符的转换规范.是不确定的行为,作为参数不是从类型转换char,short等等RESP.之前.
  • 我要求该函数在类型的每个值定义明确的方式操作int,并且printf其行为好像该参数被转化为char,short等RESP.在转换之前.
  • 也可以声称在默认参数提升之前使用不属于相应类型的参数调用函数是未定义的行为,但这似乎是深奥的.

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

Joh*_*ger 4

该标准规定:

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

[C2011 7.21.6.1/9]

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

如果您传递的参数类型比转换规范的正确类型更宽,实际会发生什么是另一个问题。我倾向于相信 C 系统不太可能被任何人实现,因此一个参数是否printf()实际上是 a char,或者它是否是一个int其值在 范围内的 an ,这会产生影响char。然而,我断言,编译器检查参数类型与格式的对应关系,并在不匹配的情况下拒绝程序是有效的行为(因为在这种情况下所需的行为是明确未定义的)。

另一方面,我当然可以想象,printf()如果参数的值超出相应转换说明符暗示的范围,那么实现实际上会表现出错误(打印垃圾、损坏内存、吃掉你的午餐)。由于行为未定义,这也是允许的。