问题
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