In Visual C++ 2012 the code
double d = 0.5;
float f = d;
int i = f;
issues 2 warnings for me:
test.cpp(26): warning C4244: 'initializing' : conversion from 'double' to 'float', possible loss of data
test.cpp(27): warning C4244: 'initializing' : conversion from 'float' to 'int', possible loss of data
I want to suppress the first warning which I consider spam, but keep the second warning which I consider very helpful. Is it possible to suppress the one and keep the other? Do people generally just suppress them all? We had a bad bug where we mistakenly passed a double to a float. But we tons of our math code would trigger the double->float warnings.
Don't suppress warnings that are designed to prevent potential bugs. Tell the compiler you know what you are doing instead by casting:
double d = 0.5;
float f = static_cast<float>(d);
int i = static_cast<int>(f);
Related
This question already has answers here:
Why should I use 'static_cast' for numeric casts in C++?
(2 answers)
Static cast to avoid IDE warnings? [closed]
(1 answer)
Why does this library refrain from using static_cast?
(1 answer)
Closed 3 months ago.
What will happen when you execute this code snippet?
#include <iostream>
int main() {
float a = 5.51;
int b = static_cast<int>(a);
std::cout << b;
}
Correct answer is:
5 will be printed on standard output, with no compilation warnings generated.
But for me would make more sense to generate compilation warning as precision would be lost. Why not?
I think it depends on compiler level of warning. In my case with Visual Studio 2022 and level warnings set to lvl 4, I get the following warning:
Warning C4305 'init': truncation from 'double' to 'float'.
As commented by #wohlstad:
The explicit cast tells the compiler you did the conversion
intenionally, and therefore there's no need for a warning. Most
compiler will issue a warning if you assign a float to an int
without a cast.
This code snippet works well on my test project. But it compiles with warnings on my working project
auto current_date = boost::gregorian::day_clock::local_day();
const auto nMinYear = current_date.year(); const auto nMonth = current_date.month(); const auto nDay = current_date.day();
const auto nMinYear1 = nMinYear + 1;
boost::gregorian::date holidayDate1(nMinYear1, nMonth, nDay);
at the line of holidayDate1 construction.
Warning C4244 'argument': conversion from 'unsigned int' to 'unsigned
short', possible loss of data
My test project is on boost-1.72 and working project on 1.75, both are on Visual Studio 2019.
And I tried using grep_year to wrap nMinYear1 -- holidayDate1(grep_year(nMinYear1 )) -- it doesn't compile.
Edit:
I just tried a forced casting can work around it,
boost::gregorian::date holidayDate1((unsigned short)nMinYear, (unsigned short)nMonth, (unsigned short)nDay);
But I don't understand why the warning happens.
The type of
nMinYear + 1
will be an unsigned int due to implicit widening of the terms in that expression. So nMinYear1 is a const unsigned int, and the compiler emits a warning when that's used in the boost::gregorian::date constructor.
decltype(nMinYear) nMinYear1 = nMinYear + 1;
is a fix.
Check out this simple program:
int main() {
float f2 = 7.2; // OK, with warning
float f3 = 7.199999809265137; // OK, no warning
float f4{ 7.2 }; // Fails
float f5{ 7.199999809265137 }; // OK, no warning
float f6 = { 7.2 }; // Fails
float f7 = { 7.199999809265137 }; // OK, no warning
}
When compiled with MSVC 2015 using the default options (cl /W4, version 19.00.23918), I get the following messages:
FloatTest.cpp(2): warning C4305: 'initializing': truncation from 'double' to 'float'
FloatTest.cpp(4): error C2397: conversion from 'double' to 'float' requires a narrowing conversion
FloatTest.cpp(4): warning C4305: 'initializing': truncation from 'double' to 'float'
FloatTest.cpp(6): error C2397: conversion from 'double' to 'float' requires a narrowing conversion
FloatTest.cpp(6): warning C4305: 'initializing': truncation from 'double' to 'float'
This program compiles fine with Clang 3.0-3.8 and GCC 4.5.4-6.1.0 (tested with http://melpon.org/wandbox), with only warnings for unused variables. Further, removing/commenting out lines f4 and f6 result in successful compilation (with only the one warning for line f2).
Initially it looks like MSVC is just telling me that 7.2 can't be represented precisely as a float, so it's a narrowing conversion (which is illegal in brace initialization). However, the standard (draft N3337), section 8.5.4, note 7, says this:
A narrowing conversion is an implicit conversion...
from long double to double or float, or from double to float, except where the source is a constant expression and the actual value after conversion is within the range of values that can be represented (even if it cannot be represented exactly)
Emphasis mine. Since 7.2 is within the range of values representable by float, its conversion to float should not be a narrowing conversion according to the standard. Is MSVC in the wrong here, and should I file a bug?
It looks like a bug, indeed. For a workaround, the following appears to silence both errors and warnings in MSVC 2015.
#pragma float_control(precise, off, push)
float f2 = 7.2; // OK, with warning
//...
#pragma float_control(precise, pop)
The same works globally if using the /fp:fast compiler switch, though that one is incompatible with /Za which disables MS language extensions.
Some floating point numbers can be exactly expressed in a float representation and some can't. If the number can be represented in the form x / 2^y where x is any integer and y is an integer 23 or less, it fits. Most decimal numbers can't be represented in this way, as a binary number they repeat forever. 7.2 is one example.
You can fix this easily by appending f to each number, to indicate to the compiler that this is a float constant rather than a double.
float f4{ 7.2f };
I have built Boost with mpi successfully, but I got lots of warnings using boost mpi under x64 platform. I am using Boost 1.59.0 + vs2015. Please help me get rid of these warnings
Here's my test code.
#include <boost/mpi/environment.hpp>
#include <boost/mpi/communicator.hpp>
#include <iostream>
namespace mpi = boost::mpi;
int main(int argc, char* argv[]) {
mpi::environment env(argc, argv);
mpi::communicator world;
std::cout << "I am process " << world.rank() << " of " << world.size()
<< "." << std::endl;
return 0;
}
And some of the warnings look like this:
1>d:\dependencies\boost_1_59_0\boost\mpi\detail\mpi_datatype_primitive.hpp(61) : warning C4267 : 'argument' : conversion from 'size_t' to 'int', possible loss of data
1>d:\dependencies\boost_1_59_0\boost\mpi\detail\mpi_datatype_primitive.hpp(80) : warning C4267 : 'argument' : conversion from 'size_t' to 'int', possible loss of data
1>d:\dependencies\boost_1_59_0\boost\mpi\detail\packed_iprimitive.hpp(62) : warning C4267 : 'argument' : conversion from 'size_t' to 'int', possible loss of data
1>d:\dependencies\boost_1_59_0\boost\mpi\detail\packed_iprimitive.hpp(106) : warning C4267 : 'argument' : conversion from 'size_t' to 'int', possible loss of data
1>d:\dependencies\boost_1_59_0\boost\mpi\detail\binary_buffer_iprimitive.hpp(64) : warning C4267 : 'argument' : conversion from 'size_t' to 'int', possible loss of data
1>d:\dependencies\boost_1_59_0\boost\mpi\detail\packed_oprimitive.hpp(52) : warning C4267 : 'argument' : conversion from 'size_t' to 'int', possible loss of data
1>d:\dependencies\boost_1_59_0\boost\mpi\detail\packed_oprimitive.hpp(96) : warning C4267 : “初始化” : conversion from 'size_t' to 'int', possible loss of data
1>d:\dependencies\boost_1_59_0\boost\mpi\detail\packed_oprimitive.hpp(100) : warning C4267 : 'argument' : conversion from 'size_t' to 'int', possible loss of data
1>d:\dependencies\boost_1_59_0\boost\mpi\detail\binary_buffer_oprimitive.hpp(53) : warning C4267 : 'argument' : conversion from 'size_t' to 'int', possible loss of data
1>d:\dependencies\boost_1_59_0\boost\mpi\detail\binary_buffer_oprimitive.hpp(87) : warning C4267 : 'argument' : conversion from 'size_t' to 'int', possible loss of data
1> d:\dependencies\boost_1_59_0\boost\archive\detail\oserializer.hpp(88) : note : see reference to function template instantiation'void boost::mpi::binary_buffer_oprimitive::save<char>(const std::basic_string<char, std::char_traits<char>, std::allocator<char>> &)'
1> d:\dependencies\boost_1_59_0\boost\archive\detail\oserializer.hpp(232) : note : see reference to function template instantiation 'void boost::archive::save_access::save_primitive<Archive, T>(Archive &, const T &)'
1> with
1>[
1> Archive = boost::mpi::packed_oarchive,
1> T = std::string
1>]
IMHO the MSVC C4267 warning is too sensitive. It even pops up when converting an int to a double. However, in this instance it may be valid, as #sjsam commented.
When I'm confident that the conversion is valid, I often disable the warning locally using:
#ifdef _MSC_VER
#pragma warning( push )
#pragma warning( disable : 4244 ) // implicit conversion, possible loss of data
#endif
before the code, and re-enable it using:
#ifdef _MSC_VER
#pragma warning( pop )
#endif
If you are confident that the boost::mpi value will never exceed std::numeric_limits<int>::max() then put them around:
#include <boost/mpi/environment.hpp>
#include <boost/mpi/communicator.hpp>
so you can disable the C4267 warning for boost::mpi only.
// Write a random number generator that returns a random folating point number between 0.0 and 1.0.
#include "stdafx.h"
#include <iostream>
#include <cmath>
#include <cstdlib>
using namespace std;
int rand_float(int n);
int main()
{
int n, i;
double r;
srand(time(NULL));
cout << "Enter number of dice to roll: ";
cin >> n;
for (i - 1; i <= n; i++) {
r = rand_float();
cout << r << endl;
}
return 0;
}
// Random Float Function
//
double rand_float() {
return (double) rand () / RAND_MAX;
}
Now the problems / Errors are
Warning 1 warning C4244: 'argument' : conversion from 'time_t' to 'unsigned int', possible loss of data
Warning 2 warning C4552: '-' : operator has no effect; expected operator with side-effect
Error 3 error C2660: 'rand_float' : function does not take 0 arguments
Warning 1 warning C4244: 'argument' : conversion from 'time_t' to 'unsigned int', possible loss of data
This is for srand(time(NULL)); where the value returned from time is larger than what fits into the parameter for srand.
This often happens for old code, as time_t has recently been made larger so that we don't run out of time values. It counts the number of seconds since 1970, which is by now quite a large number.
Warning 2 warning C4552: '-' : operator has no effect; expected operator with side-effect
This is for for (i - 1; i <= n; i++) where the first part i - 1 has no effect. You probably meant i = 1.
Error 3 error C2660: 'rand_float' : function does not take 0 arguments
You have declared the function as int rand_float(int n);, so when you call it with 0 arguments, the compiler rightly believes you should pass a value for n.
When you later define double rand_float(), the compiler believes that to be a totally different function. You are allowed to overload functions with the same name but different parameters, so this is ok according to the language, but probably not what you intended.
If this is the function you want to call from main, you should change the declaration at the top of the code to match.