C ++隐式数字类型降级

时间:2016-02-06 19:45:47

标签: c++ types casting c++14

最近,我注意到C / C ++似乎非常允许使用数字类型转换,因为它隐式地将一个double转换为int。

测试

环境:cpp.shStandard C++ 14Compilation 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

2 个答案:

答案 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
}