使用没有显式强制转换的常量调用未定义的行为



调用函数或从函数返回值时,该值需要类型为 T 的值,使用没有显式强制转换的常量文本是否会调用未定义的行为?

例如,我们有一个函数,其原型是long foo(unsigned long x);调用:foo(4); //does this invoke UB?

long foo(unsigned long x) { x += 10; return 10; } // does this invoke UB ?

我们应该写foo((unsigned long)4)return (long)10吗?

不,这一切都是明确定义的。

这两种类型之间存在隐式转换规则,因此int只是转换为unsigned long,程序按预期工作。

文字4的类型是int。(在 C 部分 6.4.4.1 整数常量中,类似的部分也可用于C++(

intunsigned long 的隐式转换在 C 和 C++ 中都有很好的定义。(在C节6.3.3.1中(

我们应该写 foo((unsigned long(4( 并返回 (long(10 吗?

您的两个示例都定义良好,因此此转换虽然可以接受,但这是多余的。

考虑以下 C 代码:

// foo.c
int foo(unsigned long x) { }

// main.c
int foo();
int main()
{
     foo(4);    // UB
     foo((unsigned long)4);   // OK
}

foo(4)调用是 UB,因为当您调用范围内没有原型的函数时,必须手动确保参数匹配。 默认参数升级发生,但仅此而已。

当然,从编写健壮代码的角度来看,编写强制转换是一个糟糕的解决方案。更好的解决方案是编写一个原型:

int foo(unsigned long);

在两个.c文件中包含的头文件中。


return 10;情况永远不能是 UB,因为编译器在函数体内编译代码时知道函数的真实返回类型。

不,这没有意义,因为这样的参数在 C 和 C++ 中都是按值传递的:

long foo(unsigned long x);

您可能会认为这是技术性的x因为参数是foo内部定义的局部自动变量,并分配了传递参数的值:

unsigned long x = 4;

如果参数类型与参数不匹配,则编译器会尝试隐式转换。例如,类型double的参数被静默转换为类型unsigned long,即使这意味着信息丢失(但您可能会收到编译器警告(。

但是,当您将x参数的类型标记为引用(仅限C++(时,您可能会遇到麻烦:

long foo(unsigned long& x);

在这里,编译器不允许你将其调用为 foo(4) ,因为你现在通过引用传递,4不能这样修改。但是,如果参数标有限定符,则可以传递它const

long foo(const unsigned long& x);

最新更新