最近,我注意到C / C ++似乎非常允许使用数字类型转换,因为它隐式地将一个double转换为int。
测试
环境:cpp.sh
,Standard C++ 14
,Compilation warnings all set
代码:
int intForcingFunc(double d) {
return d; // this is allowed
}
int main() {
double d = 3.1415;
double result = intForcingFunc(d);
printf("intForcingFunc result = %f\n", result);
int localRes = d; // this is allowed
printf("Local result = %d\n", localRes);
int staticCastRes = static_cast<int>(d); // also allowed
printf("Static cast result = %d\n", staticCastRes);
}
编译期间没有任何警告问题。
Documentation切向提到主题,但忽略了问题的确切情况:
C ++是一种强类型语言。许多转换,特别是那些暗示对值的不同解释的转换,需要显式转换,在C ++中称为类型转换。
我也尝试使用托管语言(C#),并且不允许所有这些情况(如预期的那样):
static int intForcingFunc(double d)
{
// Not legal: Cannot implicitly convert type 'double' to 'int'
// return d;
return Convert.ToInt32(d);
}
static void Main(string[] args)
{
double d = 3.1415;
double result = intForcingFunc(d);
Console.WriteLine("intForcingFunc result = " + result);
// Not legal: Cannot implicitly convert type 'double' to 'int'
// int localRes = d;
int localRes = (int)d;
Console.WriteLine("local result = " + result);
Console.ReadLine();
}
为什么强类型语言允许这种行为?在大多数情况下,这是不希望的行为。这背后的一个原因似乎是缺乏arithmetic overflow detection。
答案 0 :(得分:6)
不幸的是,这种行为是从C继承而来的,这是出了名的“#34;信任程序员&#34;在这些事情上。
隐式浮点到整数转换的确切警告标志是-Wfloat-conversion
,-Wconversion
也启用了该标志。由于某些未知原因,-Wall
,-Wextra
和-pedantic
(cpp.sh提供)不包含这些标记。
如果你使用Clang,你可以给它-Weverything
以启用字面上的所有警告。如果您使用GCC,则必须明确启用-Wfloat-conversion
或-Wconversion
以在进行此类转换时收到警告(以及您希望启用的其他有用标记)。
如果您愿意,可以将其变为错误,例如: -Werror-conversion
。
C ++ 11甚至引入了一种全新的更安全的初始化语法,称为统一初始化,您可以使用它来获取示例中隐式转换的警告,而不启用任何编译器警告:
int intForcingFunc(double d) {
return {d}; // warning: narrowing conversion of 'd' from 'double' to 'int' inside { }
}
int main() {
double d{3.1415}; // allowed
int localRes{d}; // warning: narrowing conversion of 'd' from 'double' to 'int' inside { }
}
答案 1 :(得分:1)
您没有指定使用的编译器,但实际上您可能没有启用所有警告。背后有一个故事,但实际效果是g++ -Wall
实际上并没有启用所有警告(甚至没有关闭)。其他人(例如clang ++),为了与g ++进行替换兼容,也必须这样做。
这是一篇关于为g ++设置强烈警告的好文章:https://stackoverflow.com/a/9862800/1541330
如果您使用的是clang ++,那么事情会更容易:尝试使用-Weverything
。它完全符合您的期望(打开每个警告)。您可以添加-Werror
,然后编译器将处理作为编译时错误发生的任何警告。如果您现在看到要抑制的警告(错误),只需将-Wno-<warning-name>
添加到您的命令中(例如-Wno-c++98-compat
)。
现在编译器会在出现隐式缩小转换(转换时可能没有明确要求的数据丢失)时发出警告。如果您想要进行缩小转换,则必须使用适当的强制转换,例如:
int intForcingFunc(double d) {
return static_cast<int>(d); //cast is now required
}