fuz*_*fuz 9 c printf short undefined-behavior language-lawyer
该printf系列函数提供一系列长度改性剂,其中的两个是hh(表示一个signed char或unsigned char参数升为int)和h(表示一个signed short或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转换说明符适用于指向signed char参数的指针.
h用于指定后续的d,i,o,u,x,或X转换说明适用于一个short int或unsigned short int参数(该参数将被提升根据整数促销,但它的值应被转换成short int或unsigned short int之前印刷); 或者以下n转换说明符适用于指向shortint参数的指针....
忽略n转换说明符的情况,这些几乎相同的段落对h和的行为hh有何看法?
signed char,signed short,unsigned char,或unsigned shortRESP.对于带有h或hh长度修饰符的转换规范.是不确定的行为,作为参数不是从类型转换char,short等等RESP.之前.int,并且printf其行为好像该参数被转化为char,short等RESP.在转换之前.§7.21.6.17(如果有的话)的这三种解释中的哪一种是正确的?
该标准规定:
如果任何参数不是相应转换规范的正确类型,则行为未定义。
[C2011 7.21.6.1/9]
“正确的类型”的含义可以想象,可以解释,但对我来说最合理的解释是转换规范“适用于”的类型,如同一节前面所指定的,以及部分引用的,的问题。我认为关于参数提升的括号注释是承认普通的参数传递规则,并避免这些函数是特殊情况的任何暗示。我不认为括号中的注释与确定参数的“正确类型”相关。
如果您传递的参数类型比转换规范的正确类型更宽,实际会发生什么是另一个问题。我倾向于相信 C 系统不太可能被任何人实现,因此一个参数是否printf()实际上是 a char,或者它是否是一个int其值在 范围内的 an ,这会产生影响char。然而,我断言,编译器检查参数类型与格式的对应关系,并在不匹配的情况下拒绝程序是有效的行为(因为在这种情况下所需的行为是明确未定义的)。
另一方面,我当然可以想象,printf()如果参数的值超出相应转换说明符暗示的范围,那么实现实际上会表现出错误(打印垃圾、损坏内存、吃掉你的午餐)。由于行为未定义,这也是允许的。