【发布时间】:2021-05-04 09:02:21
【问题描述】:
这段代码是未定义的行为吗?
extern long f(long x);
long g(int x)
{
return f(x);
}
根据 C11 标准,在 6.5.2.2 §6 中:
如果函数定义的类型包含原型,并且 [...] 提升后的参数类型与参数类型不兼容,则行为未定义。
在上面的例子中,函数f定义了一个包含原型的类型,参数x的类型是int,而参数x的类型是long。根据 6.2.7 §1:
如果类型相同,则两种类型具有兼容的类型。
因此,long 和 int 不兼容,所以行为未定义,对吧?
但是,在 6.5.2.2 §7 中:
如果表示被调用函数的表达式具有包含原型的类型,则参数将隐式转换为相应参数的类型,就像通过赋值一样,将每个参数的类型作为非限定版本其声明的类型。
如果我正确理解这一段,这意味着int 类型的参数x 在调用函数时隐式转换为long。根据 6.3.1.3 §1:
当整数类型的值转换为
_Bool以外的其他整数类型时,如果该值可以用新类型表示,则不变。
由于int 的排名低于long,因此每个int 变量都可以由long 变量表示。因此,参数x 可以转换为long。因此,这不是未定义的行为。
对标准的哪种解释是正确的?我的代码是未定义的行为吗?
【问题讨论】:
-
您希望
f(42)工作吗? -
@4386427
42的类型为int。我想说:“是的,它应该工作!”但看完标准后,我就不确定了。 -
第 6 段似乎主要是关于 默认参数提升,但是关于使用包含原型的类型定义的函数的部分似乎措辞不佳,因为它似乎暗示调用使用包含省略号的原型定义的函数会导致 UB。
-
关键在于推广后。因此这不是 UB。
-
@Pierre 升级后,
int参数变为long,因为long的排名更高。因此,在您的示例中没有不兼容或 UB。
标签: c type-conversion language-lawyer undefined-behavior function-call