R..*_*R.. 31 c standards printf variadic-functions language-lawyer
根据C标准(6.5.2.2第6段)
如果表示被调用函数的表达式具有不包含原型的类型,则对每个参数执行整数提升,并将具有float类型的参数提升为double.这些被称为默认参数促销.如果参数的数量不等于参数的数量,则行为未定义.如果函数是使用包含原型的类型定义的,并且原型以省略号(,...)结尾,或者促销后的参数类型与参数类型不兼容,则行为未定义.如果函数是使用不包含原型的类型定义的,并且促销后的参数类型与促销后的参数类型不兼容,则行为未定义,但以下情况除外:
- 一个提升类型是有符号整数类型,另一个提升类型是相应的无符号整数类型,并且该值可在两种类型中表示;
- 这两种类型都是指向字符类型或空格的限定或不合格版本的指针.
因此,一般来说,只要传递的值适合两种类型,传递int到需要unsigned int(或反之亦然)的可变函数是没有错的.但是,printf读取规范(7.19.6.1第9段):
如果转换规范无效,则行为未定义.如果任何参数不是相应转换规范的正确类型,则行为未定义.
签名/未签名不匹配也不例外.
这是否意味着printf("%x", 1)调用未定义的行为?
caf*_*caf 15
我认为它在技术上是未定义的,因为"正确类型" %x被指定为unsigned int- 并且正如您所指出的,这里没有签名/无符号不匹配的例外.
规则适用printf于更具体的情况,因此会覆盖一般情况的规则(对于通用的特定覆盖的另一个示例,通常允许传递NULL给期望const char *参数的函数,但是传递NULL给它的未定义行为strlen()) .
我说"技术上",因为我认为,鉴于标准中的其他限制,实施需要故意反常导致此案件出现问题.
不,因为%x格式化unsigned int,并且常量表达式1的类型是int,而它的值可表示为unsigned int.操作不是UB.
这是未定义的行为,与将整数类型的指针重新解释为相反符号的互补类型的原因相同。不幸的是,这在两个方向上都是不允许的,因为一个方向上的有效表示可能是另一个方向上的陷阱实现。
我看到从有符号到无符号的重新解释可能存在陷阱表示的唯一原因是符号表示的这种变态情况,其中无符号类型只是屏蔽了符号位。不幸的是,从标准 6.2.6.2 开始,这种情况是允许的。在这样的架构上,有符号类型的所有负值都可能是无符号类型的陷阱表示。
在您的示例中,这甚至更奇怪,因为1不允许使用无符号类型的陷阱表示。因此,要使其成为“真实”的示例,您必须使用-1.
我认为人们仍然没有为任何架构编写具有这些功能的 C 编译器,因此如果标准的新版本可以废除这种令人讨厌的情况,那么生活肯定会变得更加容易。
| 归档时间: |
|
| 查看次数: |
1730 次 |
| 最近记录: |