C++ implicit numeric type demoting

北城以北 提交于 2019-12-11 10:53:27

问题


Recently, I have noticed that C/C++ seems to be very permissible with numeric type conversion, as it implicitly casts a double to int.

Test:

Environment: cpp.sh, Standard C++ 14, Compilation warnings all set

Code:

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);
}

No warnings are issues during compilation.

Documentation mentions tangentially the subject, but misses the exact case of the question:

C++ is a strong-typed language. Many conversions, specially those that imply a different interpretation of the value, require an explicit conversion, known in C++ as type-casting.

I have also tried in a managed language (C#) and all these cases are not allowed (as expected):

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();
}

Why is this behavior allowed in a strong-typed language? In most cases, this is undesired behavior. One reason behind this seems to be lack of arithmetic overflow detection.


回答1:


Unfortunately, this behavior is inherited from C, which notoriously "trusts the programmer" in these things.

The exact warning flag for implicit floating-point to integer conversions is -Wfloat-conversion, which is also enabled by -Wconversion. For some unknown reason, -Wall, -Wextra, and -pedantic (which cpp.sh provides) don't include these flags.

If you use Clang, you can give it -Weverything to enable literally all warnings. If you use GCC, you must explicitly enable -Wfloat-conversion or -Wconversion to get a warning when doing such conversions (among other useful flags you will want to enable).

If you want, you can turn it to an error with e.g. -Werror-conversion.


C++11 even introduced a whole new safer initialization syntax, known as uniform initialization, which you can use to get warnings for the implicit conversions in your example without enabling any compiler warnings:

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 { }
}



回答2:


You did not specify what compiler you are working with, but you probably have not, in fact, enabled all warnings. There's a story behind it, but the net effect is that g++ -Wall does not actually enable all warnings (not even close). Others (eg. clang++), in order to be drop-in replacement-compatible with g++ must do the same.

Here is a great post on setting strong warnings for g++: https://stackoverflow.com/a/9862800/1541330

If you are using clang++, things will be much easier for you: try using -Weverything. It does just what you expect (turns on every warning). You can add -Werror and the compiler will then treat any warnings that occur as compile-time errors. If you are now seeing warnings (errors) that you want to suppress, just add -Wno-<warning-name> to your command (eg. -Wno-c++98-compat).

Now the compiler will warn you whenever an implicit narrowing conversion (conversion with possible data loss that you didn't explicitly ask for) occurs. In cases where you want a narrowing conversion to occur, you must use an appropriate cast, eg:

int intForcingFunc(double d) {
    return static_cast<int>(d);   //cast is now required
}


来源:https://stackoverflow.com/questions/35245625/c-implicit-numeric-type-demoting

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!