当 printf 的相应参数不是 short / char 时,使用 h 或 hh 长度修饰符是否非法?
Is it illegal to use the h or hh length modifiers when the corresponding argument to printf was not a short / char?
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 The length modifiers and their meanings are:
hh
Specifies that a following d
, i
, o
, u
, x
, or X
conversion specifier applies to a signed char
or unsigned char
argument (the argument will have been promoted according to the integer promotions, but its value shall be converted to signed char
or unsigned char
before printing); or that a following n
conversion specifier applies to a pointer to a signed char
argument.
h
Specifies that a following d
, i
, o
, u
, x
, or X
conversion specifier applies to a short int
or unsigned short int
argument (the argument will have been promoted according to the integer promotions, but its value shall be converted to short int
or unsigned short int
before printing); or that a following n
conversion specifier applies to a pointer to a short int
argument.
...
忽略 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(如果有的话)的这三种解释中哪一种是正确的?
标准规定:
If any argument is not the correct type for the corresponding conversion specification, the behavior is undefined.
[C2011 7.21.6.1/9]
"the correct type" 的含义可以想象得到解释,但对我来说最合理的解释是同一部分前面指定的转换规范 "applies to" 的类型,并且作为在问题中部分引用。我认为关于参数提升的 括号 评论承认普通的参数传递规则,并避免这些函数是特殊情况的任何暗示。我不认为括号中的评论与确定参数的 "correct type" 有关。
如果您传递的参数类型比转换规范的正确类型更宽,实际会发生什么是另一个问题。我倾向于相信 C 系统不太可能被任何人实现,以至于 printf()
参数实际上是一个 char
,还是一个 int
值在 char
范围内。但是,我断言,编译器检查参数类型与格式的对应关系并在不匹配时拒绝程序是有效的行为(因为在这种情况下所需的行为是明确未定义的)。
另一方面,如果参数的值超出相应转换说明符隐含的范围,我当然可以想象 printf()
实现实际上行为不当(打印垃圾、损坏内存、吃你的午餐) .由于行为未定义,这也是允许的。
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 The length modifiers and their meanings are:
hh
Specifies that a followingd
,i
,o
,u
,x
, orX
conversion specifier applies to asigned char
orunsigned char
argument (the argument will have been promoted according to the integer promotions, but its value shall be converted tosigned char
orunsigned char
before printing); or that a followingn
conversion specifier applies to a pointer to a signed char argument.
h
Specifies that a followingd
,i
,o
,u
,x
, orX
conversion specifier applies to ashort int
orunsigned short int
argument (the argument will have been promoted according to the integer promotions, but its value shall be converted toshort int
orunsigned short int
before printing); or that a followingn
conversion specifier applies to a pointer to a shortint
argument....
忽略 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(如果有的话)的这三种解释中哪一种是正确的?
标准规定:
If any argument is not the correct type for the corresponding conversion specification, the behavior is undefined.
[C2011 7.21.6.1/9]
"the correct type" 的含义可以想象得到解释,但对我来说最合理的解释是同一部分前面指定的转换规范 "applies to" 的类型,并且作为在问题中部分引用。我认为关于参数提升的 括号 评论承认普通的参数传递规则,并避免这些函数是特殊情况的任何暗示。我不认为括号中的评论与确定参数的 "correct type" 有关。
如果您传递的参数类型比转换规范的正确类型更宽,实际会发生什么是另一个问题。我倾向于相信 C 系统不太可能被任何人实现,以至于 printf()
参数实际上是一个 char
,还是一个 int
值在 char
范围内。但是,我断言,编译器检查参数类型与格式的对应关系并在不匹配时拒绝程序是有效的行为(因为在这种情况下所需的行为是明确未定义的)。
另一方面,如果参数的值超出相应转换说明符隐含的范围,我当然可以想象 printf()
实现实际上行为不当(打印垃圾、损坏内存、吃你的午餐) .由于行为未定义,这也是允许的。