Warning against C++ implicit conversion - c++

I have this C++ code:
#include <iostream>
#include <vector>
#include <numeric>
using namespace std;
int main() {
vector<int64_t> vec = {4294967296, 4294967296, 4294967296};
int64_t sum = accumulate(vec.begin(), vec.end(), 0, [](int64_t sum, int64_t val){
return sum + val;
});
cout << "sum = " << sum << endl;
}
It returns sum = 0 because implicit conversion from int to int64 (see 0 as third argument of accumulate function). After replacing 0 with (int64_t)0 everything works fine.
But can I detect such things in compile time? -Wconversion does not work in this case.

If the code of std::accumulate were not in a system header file, you would get the warning:
int init=0;
init += *vec.begin() //warning: conversion from 'int64_t' {aka 'long int'} to 'int' may change value [-Wconversion]
But many warnings are disabled for system header files because such warning would cause many noisy and irrelevant messages.
This behavior can be reproduced. Suppose you have this file test.hpp:
int64_t i;
int j = i;
If you compile a file test.cpp in the same directory that includes this file:
with c++ -I . test.cpp -Wconversion, the warning message is printed;
with c++ -isystem . test.cpp -Wconversion the warning message is not printed!
This is exactly what happens to header files of the standard library, the include directory is by default specified with -isystem.
The system header warning message suppression can be disabled with option -Wsystem-header
Demo
And it can be seen on the Demo the warning message is hidden within a bunch or irrelevant warning messages.

Related

I don't understand why I get this warning about conversion between signed and unsigned, is my compiler wrong? [duplicate]

This question already has answers here:
gcc size_t and sizeof arithmetic conversion to int
(2 answers)
Closed 2 years ago.
I have this code:
#include <cstdint>
#include <deque>
#include <iostream>
int main()
{
std::deque<uint8_t> receivedBytes;
int nbExpectedBytes = 1;
if (receivedBytes.size() >= static_cast<size_t>(nbExpectedBytes))
{
std::cout << "here" << std::endl;
}
return 0;
}
With -Wsign-conversion, this compiles without warning on my linux laptop, but on the embedded linux on which it's meant to run I get the following warning :
temp.cpp: In function ‘int main()’: temp.cpp:10:33: warning:
conversion to ‘std::deque::size_type {aka long unsigned
int}’ from ‘int’ may change the sign of the result [-Wsign-conversion]
if (receivedBytes.size() >= static_cast<size_t>(nbExpectedBytes))
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
I just don't understand:
I have -Wsign-conversion enabled both on my linux laptop and on the embedded linux, so why do I only get the warning on the embedded linux?
I'm explicitly casting from int to size_t (which should not produce a warning because the cast is explicit), then comparing a size_t to a std::deque<unsigned char>::size_type, so where is the implicit conversion from signed to unsigned that triggers the warning??!
I can't help but think the compiler on the embedded linux is wrong here. Am I missing something?
Edit: On my linux laptop I'm using g++ version 9.3.0, while on the embedded linux I'm using g++ version 6.3.0 (probably not the usual binary since it's an ARM64 architecture)
This is undoubtedly a bug/error in the embedded compiler. Separating the static_cast from the >= comparison removes the warning, as can be seen from testing the following code on Compiler Explorer, with ARM64 gcc 6.3.0 (linux) selected:
#include <deque>
#include <cstddef>
#include <cstdint>
int main()
{
std::deque<uint8_t> receivedBytes;
int nbExpectedBytes = 1;
// Warning generated ...
while (receivedBytes.size() >= static_cast<size_t>(nbExpectedBytes))
{
break;
}
// Warning NOT generated ...
size_t blob = static_cast<size_t>(nbExpectedBytes);
while (receivedBytes.size() >= blob)
{
break;
}
return 0;
}
Further, the warning also disappears when changing to the (32-bit) ARM gcc 6.3.0 (linux) compiler.

no warnings in QT creator

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?
^

How to silence long long integer constant warning from GCC

I have some code using large integer literals as follows:
if(nanoseconds < 1'000'000'000'000)
This gives the compiler warning integer constant is too large for 'long' type [-Wlong-long]. However, if I change it to:
if(nanoseconds < 1'000'000'000'000ll)
...I instead get the warning use of C++11 long long integer constant [-Wlong-long].
I would like to disable this warning just for this line, but without disabling -Wlong-long or using -Wno-long-long for the entire project. I have tried surrounding it with:
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wlong-long"
...
#pragma GCC diagnostic pop
but that does not seem to work here with this warning. Is there something else I can try?
I am building with -std=gnu++1z.
Edit: minimal example for the comments:
#include <iostream>
auto main()->int {
double nanoseconds = 10.0;
if(nanoseconds < 1'000'000'000'000ll) {
std::cout << "hello" << std::endl;
}
return EXIT_SUCCESS;
}
Building with g++ -std=gnu++1z -Wlong-long test.cpp gives test.cpp:6:20: warning: use of C++11 long long integer constant [-Wlong-long]
I should mention this is on a 32bit platform, Windows with MinGW-w64 (gcc 5.1.0) - the first warning does not seem to appear on my 64bit Linux systems, but the second (with the ll suffix) appears on both.
It seems that the C++11 warning when using the ll suffix may be a gcc bug. (Thanks #praetorian)
A workaround (inspired by #nate-eldredge's comment) is to avoid using the literal and have it produced at compile time with constexpr:
int64_t constexpr const trillion = int64_t(1'000'000) * int64_t(1'000'000);
if(nanoseconds < trillion) ...

C++ Type Check in Functions ignored (required double, provided int)

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)

Compilation error while using to_string in c++ program

To get precision and scale of a number i am using this simple program. But while converting number into string it is giving compilation error.
g++ precision.cpp
precision.cpp: In function ‘int main()’:
precision.cpp:6: error: ‘to_string’ was not declared in this scope
When I compile with the -std=c++0x switch I get
g++ precision.cpp -std=c++0x
precision.cpp: In function ‘int main()’:
precision.cpp:6: error: call of overloaded ‘to_string(int)’ is ambiguous
/usr/lib/gcc/i686-redhat-linux/4.4.4/../../../../include/c++/4.4.4/bits/basic_string.h:2604: note: candidates are: std::string std::to_string(long long int)
/usr/lib/gcc/i686-redhat-linux/4.4.4/../../../../include/c++/4.4.4/bits/basic_string.h:2610: note: std::string std::to_string(long long unsigned int)
/usr/lib/gcc/i686-redhat-linux/4.4.4/../../../../include/c++/4.4.4/bits/basic_string.h:2616: note: std::string std::to_string(long double)
The source code looks like this:
#include <iostream>
#include <string>
using namespace std;
int main()
{
string value = to_string(static_cast<int>(1234));
int precision = value.length();
int scale = value.length()-value.find('.')-1;
cout << precision << " " << scale;
return 0;
}
What is causing this error?
The first error is because std::to_string is a C++11 feature, and GCC by default compiles in C++03 mode.
The second error, when you are using the correct flag, is probably because the support for C++11 in GCC 4.4 (which you seem to be using) is quite minimal. As you can see by the error messages, the compiler shows you the alternatives it have.
By the way, you don't need to cast integer literals to int, they are of type int by default. You might want to cast it to long double though, as that's one of the valid overloads and you seems to want to find the decimal point (the code will not work as expected if there is no decimal point in the string, like when converting an integer).
I recommend to use boost::lexical_cast instead.