I look for a warning compilation flag of g++ that will prevent silent conversion from bool to double.
This answer relates to a broader question of conversion of int to double. The question was dismissed there because it's considered a lossless conversion and perfectly legal.
However, since bool has another semantic meaning than simple integer, I expect that an implicit conversion from bool to double will issue a warning.
I've tried:
-Wall -Wextra -pedantic -Wconversion
on the following code without any success (no warning issued):
#include <iostream>
int foo(double var){
return static_cast<int>(var);
}
int main(){
std::cout << foo(5) << std::endl;
std::cout << foo(5.1) << std::endl;
std::cout << foo(false) << std::endl; // here I want the warning
return 0;
}
I use g++ 4.9.2, but an answer suggesting using higher version is perfectly acceptable.
Thanks.
This is an approach that has nothing to do with gcc, but instead relies on another tool: clang-tidy has a readability-implicit-bool-conversion check that will warn you in this case. You need a separate static analysis check (which might take long to run, depending on your code base), but it works:
clang-tidy --checks=readability-implicit-bool-conversion your-file.cpp
yields
[...] warning: implicit conversion bool -> 'double' [readability-implicit-bool-conversion]
std::cout << foo(false) << std::endl; // here I want the warning
^~~~~
0.0
The real problem is the implicit conversion from bool to int (which is followed by a second conversion to double).
Booleans were added lately to the C++ language and never really considered semantically different from a number (just as there is no true character type).
As there is no narrowing of the type, finding a warning condition is difficult.
If you have the option of turning the bools to a custom class (maybe just temporarily), you can overload the conversion operators.
Related
I have code from over 20 years in C/C++ and one technique used to handle variable data sizes was to let automatic type conversion handle it.
For example:
#define MY_STATUS_UNDEFINED (-1)
Then if it was compared/used against a int64_t it was auto expanded to -1LL, for uint64_t to 0xFFFFFFFFFFFFFFFF, for uint32_t to 0xFFFFFFFF, int16_t to -1, uint16_t to 0xFFFF, etc..
However, now I'm getting errors with the newer gcc versions that complain about narrowing conversion. In this case it was a switch statement with a UINT variable.
switch (myuint) {
case MY_STATUS_UNDEFINED:
break;
}
What is the recommended way to get it to not error out?
What is the easiest way to get it to not error out?
What is the cleanest way so it doesn't error out and doesn't give any warning message?
Essentially, I want it to do the auto type conversion properly but no warning or errors.
Using the following brief example:
#include <cstdint>
#include <iostream>
#define MY_STATUS_UNDEFINED (-1)
void bar()
{
std::cout << "It works\n";
}
void foo(uint32_t n)
{
switch (n) {
case MY_STATUS_UNDEFINED:
bar();
break;
}
}
int main()
{
foo(0xFFFFFFFF);
return 0;
}
You are seeing the following error from gcc:
error: narrowing conversion of ‘-1’ from ‘int’ to ‘unsigned int’ [-Wnarrowing]
Now, pay careful attention to the error message. gcc is telling the exact option to shut this off. See the [-Wnarrowing] annotation? That's the compilation flag that's responsible for producing this error message.
To turn it off, stick a "no-" in front of it:
-Wno-narrowing
All gcc diagnostics use this convention. Now the shown code will compile, run, and produce the expected result:
It works!
Add -Wno-narrowing to your global compilation options.
You should really consider this to be only a temporary band-aid solution. These compilation errors are exactly what you want. They're telling you about real or potential problems. -Wall -Werror -Wsuggest-override -Wreturn-type are my favorite compilation options.
There is a simple a program:
#include <iostream>
int main()
{
int i = 1;
double x = 2.5;
x =i; // I do not want this can be compiled with no warning
// I want only x=(double)i, or x=std::static_cast<double>i, that can compiled with no warning.
std::cout << "x = " << x << std::endl;
return 0;
}
I do not want implicit conversion from int to double in my program.
I want the compiler show warning unless I explicitly told the compiler it should be a conversion.
I compiled the program with GNU compiler g++ or intel C++ compiler icpc, there is no warning.
g++ main.cpp -Wall
icpc main.cpp -Wall
Is there something I can configure to implement the strict type conversion checking?
I am working in C++11, the C solution is also appreciated.
Thanks for your time.
I believe you are looking for these warning flags:
-Wconversion
-Warith-conversion
-Warith-conversion
Do warn about implicit conversions from arithmetic operations even when conversion of the operands to the same type cannot change their values. This affects warnings from -Wconversion, -Wfloat-conversion, and -Wsign-conversion.
void f (char c, int i)
{
c = c + i; // warns with -Wconversion
c = c + 1; // only warns with -Warith-conversion
}
https://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html#Warning-Options
EDIT:
If this isn't enough for you then you might be running into a bit of a wall.
But there are possible alternatives.
https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#Res-narrowing
There is a coreguideline that covers narrowing conversion issues.
While coreguidelines aren't generally covered by compilers other static analyzer tools might be up your alley.
Clang-tidy:
https://clang.llvm.org/extra/clang-tidy/checks/cppcoreguidelines-narrowing-conversions.html
Cpp-core-check:
https://devblogs.microsoft.com/cppblog/c-core-check-in-visual-studio/
If none of these are the solution then what you are looking it as completely legal conversions that are specified by C++. Because everything I'm describing/linking is to narrowing conversions. If your code won't cause a narrowing conversion then I don't believe any tool will currently catch this (as far as I know). Because it is completely legal C++.
I have the following code
#include <iostream>
using namespace std;
int dmult(int a, int b){
return 2*a*b;
}
int main(void)
{
double a = 3.3;
double b = 2;
int c = dmult(a,b);
cout << c << endl;
return 0;
}
It compiles with MinGW without problems. The result is (as I thought) false. Is it a problem of the compiler that there is no warning, that a function expecting integers, but fed with doubles, can compile without warning even if the input type is wrong? Does it mean that C++ ignores the input type of a function? Shouldn't it realize that the function arguments have the wrong type?
double's are implicitly convertible to ints (and truncated), and the compiler is not forced by the standard to emit a warning (it tries its best to perform the conversion whenever possible). Compile with -Wconversion
g++ -Wconversion program.cpp
and you'll get your warning:
warning: conversion to 'int' from 'double' may alter its value [-Wfloat-conversion]
The typical warning flags -Wall -Wextra don't catch it since many times it is the programmer's intention to truncate double's to int's.
Live example here.
c++ automatically casts floats and doubles to integer literals by truncating them. so 3.3 becomes 3 when you call dmult(3.3,2)
Consider the following code:
void f(int x)
{
std::cout << x << std::endl;
}
int main()
{
double x = 1.5;
f(x);
return 0;
}
This compiles and runs without any warnings (using -Wall), and therefore hides a dangerous implicit cast from double to int. The compiler will catch the cast if the function is called with a literal, i.e.
f(1.5)
but this isn't all that useful. Why don't these compilers give warnings for this cast? I'm on OSX 10.8.3 with gcc-4.2.1 and clang-425.0.28.
For posterity:
In order to avoid implicit conversions, use the -Wconversion flag (it's not included in -Wall). Clang actually includes -Wconversion in the -Weverything flag, but this flag enables quite a bit more warnings than most users are accustomed to.
I often use assignment of "longer" typed variables to "shorter" ones, for example int to short or uint32_t to uint8_t. One day i decided to find all such cases in my code using gcc, but found to my amazement that gcc didn't output any warnings!
int long_value;
short short_value;
std::cin >> long_value; // Example input: 32769
short_value = long_value; // MS Visual Studio complains here at warning level 4
std::cout << "Long: " << long_value << '\n'; // My example output: 32769
std::cout << "Short: " << short_value << '\n'; // My example output: -32767
Using gcc -Wall or gcc -Wconversion didn't help (gcc didn't output any warning). Actually, it never output any warning for any input and output type (e.g. long and unsigned char).
I have never found an actual bug in gcc so i am almost sure this behavior has a reason.
So why no warning?
Update: i use gcc 4.1.2.
This feature was added in gcc 4.3 version. Previously this was not available.
I hope you are using gcc version 4.2 or below.
http://gcc.gnu.org/wiki/NewWconversion confirms this.
This bug: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=2707 also talks about it.
I can't reproduce that. Compiling this code with gcc 4.4.5 with -Wconversion, I get
a.cc: In function ‘void f()’:
a.cc:7: warning: conversion to ‘short int’ from ‘int’ may alter its value