调用函数或从函数返回值时,该值需要类型为 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++(
从 int
到 unsigned 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);