是在没有显式强制转换的情况下使用常量调用未定义的行为吗?
is using a constant without an explicit cast invoke undefined behavior?
在调用函数或从函数返回值时,期望类型为 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)
should we write foo((unsigned long)4) and return (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,因为编译器在编译函数体内的代码时,函数的真实 return 类型是已知的。
不,这没有意义,因为这样的参数在 C 和 C++ 中都是按值传递的:
long foo(unsigned long x);
你可能会认为它是技术上的,因为 x
参数是在 foo
中定义的局部自动变量,并分配了传递参数的值:
unsigned long x = 4;
如果参数类型与参数不匹配,则编译器会尝试隐式转换。例如,double
类型的参数被静默转换为 unsigned long
类型,即使这意味着信息丢失(尽管您可能会收到编译器警告)。
然而,当您将 x
参数的类型标记为 reference(仅限 C++)时,您可能会遇到麻烦:
long foo(unsigned long& x);
在这里,编译器不允许您将其称为foo(4)
,因为您现在是通过引用传递,而4
不能这样修改。但是,如果参数标有 const
限定符:
,则可以传递它
long foo(const unsigned long& x);
在调用函数或从函数返回值时,期望类型为 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)
should we write foo((unsigned long)4) and return (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,因为编译器在编译函数体内的代码时,函数的真实 return 类型是已知的。
不,这没有意义,因为这样的参数在 C 和 C++ 中都是按值传递的:
long foo(unsigned long x);
你可能会认为它是技术上的,因为 x
参数是在 foo
中定义的局部自动变量,并分配了传递参数的值:
unsigned long x = 4;
如果参数类型与参数不匹配,则编译器会尝试隐式转换。例如,double
类型的参数被静默转换为 unsigned long
类型,即使这意味着信息丢失(尽管您可能会收到编译器警告)。
然而,当您将 x
参数的类型标记为 reference(仅限 C++)时,您可能会遇到麻烦:
long foo(unsigned long& x);
在这里,编译器不允许您将其称为foo(4)
,因为您现在是通过引用传递,而4
不能这样修改。但是,如果参数标有 const
限定符:
long foo(const unsigned long& x);