I can't see almost any warnings in my program.
My cpp file:
#include <iostream>
using namespace std;
int main()
{
long long int ll = 100000000067;
unsigned short sh = ll; //no warning here, why?
cout << sh << " " << ll << endl;
int s; //warning only here: warning: unused variable āsā [-Wunused-variable]
return 0;
}
My pro file:
TEMPLATE = app
CONFIG += console c++11
CONFIG -= app_bundle
CONFIG -= qt
SOURCES += main.cpp
QMAKE_CXXFLAGS += -Wall -Wextra -pedantic
I try use project with cmake, but the results are this same.
According to GCC documentation
-Wconversion
Warn for implicit conversions that may alter a value. This includes conversions between real and integer, like abs (x) when x is double; conversions between signed and unsigned, like unsigned ui = -1; and conversions to smaller types, like sqrtf (M_PI). Do not warn for explicit casts like abs ((int) x) and ui = (unsigned) -1, or if the value is not changed by the conversion like in abs (2.0). Warnings about conversions between signed and unsigned integers can be disabled by using -Wno-sign-conversion.
For C++, also warn for confusing overload resolution for user-defined conversions; and conversions that never use a type conversion operator: conversions to void, the same type, a base class or a reference to them. Warnings about conversions between signed and unsigned integers are disabled by default in C++ unless -Wsign-conversion is explicitly enabled.
For me your example with -Wconversion generates
~/main.cpp:9: warning: conversion to 'short unsigned int' from 'long long int' may alter its value [-Wconversion]
unsigned short sh = ll; //no warning here, why?
^
Related
I compiled the following code with -Wsign-conversion :
int main()
{
unsigned int a = 8;
int b = a + 8u; // warning: implicit conversion changes signedness: 'unsigned int' to 'int'
int c = a - 8u; // warning: implicit conversion changes signedness: 'unsigned int' to 'int'
int d = a * 8u; // warning: implicit conversion changes signedness: 'unsigned int' to 'int'
int e = a / 8u; // gcc warns, but no warning in clang
}
Clang doesn't emit a warning when assigning from the result of an unsigned division, but gcc does.
Why is there a difference in this one particular case?
Clang is just being an extra bit clever: division of an unsigned integer by an unsigned integer larger or equal to 2 means the unsigned integer result will always fit in the signed integer counterpart (to that of the numerator type in the division expression). However, if you divide by an unsigned integer valued 1, the result is no longer guaranteed to fit in a signed integer counterpart, and Clang does emit a warning:
#include <cstdint>
int main() {
uint8_t a = 240; // '240 / 1' will not fit in int8_t
int8_t e = a / 2u; // No warning in clang
int8_t f = a / 1u; // warning: implicit conversion changes signedness: 'unsigned int' to 'int8_t' (aka 'signed char') [-Wsign-conversion]
}
One could also argue that Clang should be able to omit the warning for the similar special case of multiplication by 0; however Clang does not whereas GCC, instead, does:
// Clang warns, no warning in GCC.
int8_t g = a * 0u;
So peculiarly Clang is clever, in this context, w.r.t. division and GCC w.r.t. multiplication.
Finally, note that the gating for Clang to emit this warning during division seems to be only when dividing by 1, as you will not get the same -Wsign-conversion if you divide by 0u; arguably as it has been overridden by the more relevant (in such a context) -Wdivision-by-zero warning:
int8_t h = a / 0u;
warning: division by zero is undefined [-Wdivision-by-zero]
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++.
#include <iostream>
using namespace std;
int main() {
unsigned int u = 5;
int x = -1;
if(x>u) {
cout<<"Should not happen"<<endl;
} else {
cout<<"Ok"<<endl;
}
}
This code outputs Should not happen. I came across this when comparing the size of a string (size_t is an unsigned int or unsigned long long value) to an int.
It seems that C type casts int to unsigned int but in practice, it seems it would bring in bugs. Honestly, I would have preferred a compile-time error given how incompatible int is to unsigned int. I would like to know why the convention is like this?
You can enable -Wsign-compare -Werror in Clang: Try it online!
It'll produce a compile-time error (because of -Werror that treats warnings as errors):
.code.tio.cpp:7:9: error: comparison of integers of different signs: 'int' and 'unsigned int' [-Werror,-Wsign-compare]
if(x>u) {
~^~
1 error generated.
For some reason, -Wall -Werror in Clang (but not in GCC) doesn't produce any errors. But -Wall -Wextra -Werror does include -Wsign-compare, so you can use that.
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)
Both clang 2.9 and g++ 4.1.2 will generate a warning when the variable x is declared constant in the code snippet below. However when const is removed, as it has been in the snippet, neither of the compilers generates a warning even when executed with the following parameters which are the strictest I know: "-Wall -Wextra -pedantic -ansi"
Why won't the compilers deduce and report the same warning since x isn't volatile and cannot possibly be modified before the type conversion?
#include <iostream>
int main(int argc, char **argv)
{
unsigned int x = 1000;
const unsigned char c = x;
const unsigned int x_ = c;
std::cout << "x=" << x << " x_=" << x_ << std::endl;
return 0;
}
With const unsigned int x = 1000; g++ provides the message "warning: large integer implicitly truncated to unsigned type" and clang "warning: implicit conversion from 'const unsigned int' to 'const unsigned char' changes value from 1000 to 232 [-Wconstant-conversion]".
Is there any way to automatically detect this case without manually inspecting the code or relying on correctly designed unit tests?
For GCC, add the flag -Wconversion and you will get the desired warning. It's not a part of -Wall since so much code just ignores these types of things. I always have it turned on since it finds otherwise hard to debug defects.
If it is a const the compiler can see its value and warn about the truncation. If it is not a const, it cannot, despite the initialisation. This:
const unsigned int x = 1000;
const unsigned char c = x;
is equivalent to:
const unsigned char c = 1000;
I've run gcc with -O3 -fdump-tree-vrp, and what I see in the dump is:
std::__ostream_insert<char, std::char_traits<char> > (&cout, &"x="[0], 2);
D.20752_20 = std::basic_ostream<char>::_M_insert<long unsigned int> (&cout, 1000);
std::__ostream_insert<char, std::char_traits<char> > (D.20752_20, &" x_="[0], 4);
D.20715_22 = std::basic_ostream<char>::_M_insert<long unsigned int> (D.20752_20, 232);
i.e. it just inlines the constants 1000 and 232 in the cout statement!
If I run it with -O0, it doesn't dump anything, despite -ftree-vrp and -ftree-ccp switches.
Seems like gcc inlines the constants before it can emit the warnings...