在调用函数或从函数返回值时,需要类型为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
??
答案 0 :(得分:6)
不,这一切都很明确。
两种类型之间存在隐式转换规则,因此int
只是转换为unsigned long
,程序按预期工作。
答案 1 :(得分:3)
文字4
的类型为int
。 (在C部分6.4.4.1整数常量中,类似的部分也可用于C ++)
从int
到unsigned long
的隐式转换在C和C ++中都有明确的定义。 (在C部分6.3.3.1中)
我们应该写foo((unsigned long)4)并返回(long)10?
您的两个示例都已明确定义,因此这种转换虽然可以接受但是多余的。
答案 2 :(得分:0)
考虑这个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,因为编译器在编译函数体内的代码时,函数的真实返回类型是已知的。
答案 3 :(得分:0)
不,这没有意义,因为这样的参数在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);