I try to follow the mantra of "no warnings." I try to write my code so that the compiler gives no warnings. I'm starting to use non-standard libraries for the first time.
I recently installed mlpack (with armadillo) using
vcpkg install mlpack:x64-windows
I built the library and it works. However, my compiler gives loads of warnings. These warnings seem like they could have been fixed by the developer, but I'm not sure.
Many of the warnings are about conversions. For example, the first such compiler warning is
'argument': conversion from 'size_t' to 'const arma::arma_rng::seed_type', possible loss of data
This occurs in the line
arma::arma_rng::set_seed(seed);
where seed is always of type const size_t. I made the following change:
arma::arma_rng::set_seed(static_cast<arma::arma_rng::seed_type>(seed));
This removed the warning. Another fix is to overload arma::arma_rng::set_seed to take a double and perform the conversion within the function.
Given that the armadillo library is so popular, I assume someone at some point would have recommended these changes. Is there a reason not to add static_cast here (i.e., is this an optimization)?
I dont have the library available, so I'll use a different example. Consider the following code is in the library. Its a completely made up example, but I hope it resembles the situation more or less:
#include <iostream>
void foo(unsigned char x) {
std::cout << (int)x << "\n";
}
void bar_warn(int a){
foo(a);
}
void bar_no_warn(int a){
foo(static_cast<unsigned char>(a));
}
gcc warns for bar_warn but not for bar_no_warn:
<source>:4:9: error: conversion from 'int' to 'unsigned char' may change value [-Werror=conversion]
4 | foo(a);
| ^
The std::cout << (int)x is just to see the effect of following user code:
int main() {
bar_warn(123456);
bar_no_warn(123456);
}
Output is
64
64
That is: The user code is completely fine. It has no errors nor does it trigger warnings. The issue is in the library code. The cast does change the value. And that is the case with or without the static cast. The static cast does not "fix" the cast in any way, it merely silences the warning.
If you can browse all usages of the cast and make sure that the reason for the warning never takes place then you can use a static_cast to silence the warning. In library code that is not always possible. The library cannot foresee all usages. User code might pass a value that is too big and a user might get unexpected results. In such case it is better for the library to warn rather than to silence the warning.
If you are bothered by the warning you can still silence it. For example gcc has -isystem to not output warnings in system headers. I suppose other compilers have similar option.
Related
C++ compilers happily compiles this code, with no warning:
int ival = 8;
const char *strval = "x";
const char *badresult = ival + strval;
Here we add a char* pointer value (strval) to an int value (ival) and store the result in a char* pointer (badresult). Of course, the content of the badresult will be total garbage and the app might crash on this line or later when it is trying to use the badresult elsewhere.
The problem is that it is very easy to make such mistakes in real life. The one I caught in my code looked like this:
message += port + "\n";
(where message is a string type handling the result with its operator += function; port is an int and \n is obviously a const char pointer).
Is there any way to disable this kind of behavior and trigger an error at compile time?
I don't see any normal use case for adding char* to int and I would like a solution to prevent this kind of mistakes in my large code base.
When using classes, we can create private operators and use the explicit keyword to disable unneeded conversions/casts, however now we are talking about basic types (char* and int).
One solutions is to use clang as that has a flag to enable warning for this.
However I can't use clang, so I am seeking for a solution that triggers a compiler error (some kind of operator overload or mangling with some defines to prevent such constructs or any other idea).
Is there any way to disable this kind of behavior and trigger an error at compile time?
Not in general, because your code is very similar to the following, legitimate, code:
int ival = 3;
const char *strval = "abcd";
const char *goodresult = ival + strval;
Here goodresult is pointing to the last letter d of strval.
BTW, on Linux, getpid(2) is known to return a positive integer. So you could imagine:
int ival = (getpid()>=0)?3:1000;
const char *strval = "abcd";
const char *goodresult = ival + strval;
which is morally the same as the previous example (so we humans know that ival is always 3). But teaching the compiler that getpid() does not return a negative value is tricky in practice (the return type pid_t of getpid is some signed integer, and has to be signed to be usable by fork(2), which could give -1). And you could imagine more weird examples!
You want compile-time detection of buffer overflow (or more generally of undefined behavior), and in general that is equivalent to the halting problem (it is an unsolvable problem). So it is impossible in general.
Of course, one could claim that a clever compiler could warn for your particular case, but then there is a concern about what cases should be useful to warn.
You might try some static source program analysis tools, perhaps Clang static analyzer or Frama-C (with its recent Frama-C++ variant) - or some costly proprietary tools like Coverity and many others. These tools don't detect all errors statically and takes much more time to execute than an optimizing compiler.
You could (for example) write your own GCC plugin to detect such mistakes (that means developing your own static source code analyzer). You'll spend months in writing it. Are you sure it is worth the effort?
However I can't use clang,
Why? You could ask permission to use the clang static analyzer (or some other one), during development (not for production). If your manager refuses that, it becomes a management problem, not a technical one.
I don't see any normal use case for adding char* to int
You need more imagination. Think of something like
puts("non-empty" + (isempty(x)?4:0));
Ok that is not very readable code, but it is legitimate. In the previous century, when memory was costly, some people used to code that way.
Today you'll code perhaps
if (isempty(x))
puts("empty");
else
puts("non-empty")
and the cute thing is that a clever compiler could probably optimize the later into the equivalent of former (according to the as-if rule).
No way. It is valid syntax, and very useful in many cases.
Just think about you were to write int b=a+10 but you wrote int b=a+00 incorrectly, the compiler won't know it is an error by mistake.
However, you can consider to use C++ classes. Most C++ classes are well designed to prevent such obvious mistakes.
In the first example in your question, really, compilers should issue a warning. Compilers can trivially see that the addition resolves to 8 + "x" and clang does indeed optimise it to a constant. I see the fact it doesn't warn about this as a compiler bug. Although compilers are not required to warn about this, clang goes through great efforts to provide useful diagnostics, and it would be an improvement to diagnose this as well.
In the second example, as Matteo Italia pointed out, clang does already provide a warning option for this, enabled by default: -Wstring-plus-int. You can turn specific warnings into errors by using -Werror=<warning-option>, so in this case -Werror=string-plus-int.
In the following code:
#include <iostream>
int main()
{
const long l = 4294967296;
int i = l;
return i; //just to silence the compiler
}
the compiler warns about implicit conversion (using -Wall and -std=c++14) as following:
warning: implicit conversion from 'const long' to 'int' changes value from 4294967296 to 0 [-Wconstant-conversion]
which is ok. But there is no warning if the conversion is from double to int, as in the following code:
#include <iostream>
int main()
{
const double d = 4294967296.0;
int i = d;
return i; //just to silence the compiler
}
Why the compiler reacts differently in these situations?
Note 1: clang version is 3.6.2-svn240577-1~exp1
Note 2: I've tested it with many others versions of gcc, clang and icc thanks to Compiler Explorer (gcc.godbolt.org). So all tested versions of gcc (with exception of 5.x) and icc threw the warning. No clang version did it.
The conversion from double to an integer type changes the value "by design" (think to 3.141592654 converted to an int).
The conversion from long int to int instead may or work or may be undefined behavior depending on the platform and on the value (the only guarantee is that an int is not bigger than a long int, but they may be the same size).
In other words the problems in the conversions between integer types are incidental artifacts of the implementation, not by-design decisions. Warning about them is better especially if it can be detected at compile time that something doesn't work because of those limitations.
Note also that even conversion from double to int is legal and well defined (if done within boundaries) and an implementation is not required to warn about it even when the loss of precision can be seen at compile time. Compilers that warn too much even when the use could be meaningful can be a problem (you just disable warnings or even worse get the habit of accepting a non-clean build as normal).
These implicit conversion rules may add up with other C++ wrinkles getting to truly odd-looking and hard to justify behaviors like:
std::string s;
s = 3.141592654; // No warnings, no errors (last time I checked)
Don't try to use too much logic with C++. Reading specs works better.
Well, by reading this great article named "What Every C Programmer Should Know About Undefined Behavior", specially part #3/3, at LLVM Project Blog, written by Chris Lattner - the main author of LLVM - I could understand better the Clang's Approach to Handling Undefined Behavior.
So, in order to guarantee your strong appeal for optimization and time economy - "ultimate performance" -
Keep in mind though that the compiler is limited by not having dynamic
information and by being limited to what it can without burning lots
of compile time.
Clang doesn't run all related undefined behavior checks by default,
Clang generates warnings for many classes of undefined behavior
(including dereference of null, oversized shifts, etc) that are
obvious in the code to catch some common mistakes.
instead of this, Clang and LLVM provides tools like Clang Static Analyzer, Klee project, and the -fcatch-undefined-behavior (now UndefinedBehaviorSanitizer - UBSan - ) to avoid these possible bugs.
By running UBSan in the presented code, clang++ with the following argument -fsanitize=undefined the bug will be catched as following:
runtime error: value 4.29497e+09 is outside the range of representable values of type 'int'
Considering the following piece of code:
#include <iostream>
auto main() -> int {
double x(7.0);
int i{x};
std::cout << "i = " << x << std::endl;
return 0;
}
When compiled in GCC4.9 it compiles fine with only a warning:
warning: narrowing conversion of ‘x’ from ‘double’ to ‘int’ inside { }
Compiling with either Clang3.3 or VC++2013 gives a compile error:
error: type 'double' cannot be narrowed to 'int' in initializer list
error C2397: conversion from 'double' to 'int' requires a narrowing
Questions:
Which of the compilers is right according to the standard?
Is there any reason why the compilers mentioned above should exhibit such diverse behaviour?
The answer
Both compilers are correct!
Explanation
The Standard doesn't distinguish between an error and a warning, both go under the category of Diagnostics.
1.3.6 diagnostic message [defns.diagnostic]
message belonging to an implementation-defined subset of the implementation's output messages
Since the Standard says that a diagnostic is required in case a program is ill-formed, such as when a narrowing-conversion takes place inside a braced-initializer, both compilers are confirming.
Even if the program is ill-formed from the Standards point of view, it doesn't mandate that a compiler halts compilation because of that; an implementation is free to do whatever it wants, as long as it issues a diagnostic.
The reason for gcc's behavior?
Helpful information was provided by #Jonathan Wakely through comments on this post, below are a merge of the two comments;
he exact reason is that GCC made it an error at one point and it broke ALL THE PROGRAMS so it got turned into a warning instead. Several people who turned on the -std=c++0x option for large C++03 codebases found harmless narrowing conversions to cause most of the porting work to go to C++11See e.g. PR 50810 where Alisdair reports narrowing errors were >95% of the problems in Bloomberg's code base.In that same PR you can see that unfortunately it wasn't a case of "let's just issue a warning and be done with it" because it took a lot of fiddling to get the right behaviour.
I'm working on a school project that involves porting a large piece of C++ code on an experimental piece of hardware. Unfortunately, that hardware is 64-bit and the code contains many instances of pointer arithmetic that expects pointers to be 32-bit, i.e. it often does reinterpret_cast<uint32_t>(ptr).
Going through them one by one would be very tedious and since this is an experimental project anyway, I'm happy to settle for a "hackish" workaround. So instead I modified the implementation of malloc to ensure it never allocates memory above the 4GB limit. Technically, these casts should therefore be valid.
Question is, how do I explain this to Clang? The error I'm getting is: error: cast from pointer to smaller type 'uint32_t' (aka 'unsigned int') loses information. Is there a way to disable it?
Thanks,
David
I was able to disable this with -fms-extensions after getting this from someone on the Cpplang Slack:
Looking at "DiagnosticSemaKinds.td" it shows up as err_bad_reinterpret_cast_small_int, https://github.com/llvm-mirror/clang/blob/release_50/include/clang/Basic/DiagnosticSemaKinds.td#L6193
There are two occurences in "SemaCast.cpp" -- one of which suggests it's sensitive to MS extensions, https://github.com/llvm-mirror/clang/blob/release_50/lib/Sema/SemaCast.cpp#L2112
One could try -fms-extensions (hopefully not -fms-compatibility), but that would bring all the shebang with it.
I agree that you should bite the bullet and fix the code to use the correct integer type. But to answer your question: No, you can't disable it, though you can work around it.
Many errors come from warnings. A good thing in general, but if you want to disable the warning, just do it. Since the culprit is probably something like -Wall which enables many warnings you should keep on, you should selectively disable this single warning. The error message mentions the diagnostic responsible for error message, e.g. ... [-Wextra-tokens] (if it doesn't, remove the -fno-diagnostics-show-option flag). You can then disable this diagnostic completely by adding -Wno-extra-tokens (again, the "extra tokens" warning is an example), or turn it into a non-fatal warning by means of -Wno-error=extra-tokens.
However, this specific error is not due to a warning and I can't find any option to disable errors (makes sense, since most errors are fatal).
But to just truncate the integer value and not having to fix all the wrong uses of uint32_t just yet, you could use static_cast<uint32_t>(reinterpret_cast<uintptr_t>(ptr)). Needless to say, this will still be wrong.
how about using uintptr_t, most of your pointer arithmetic may still works.
Save this piece of code as mycast.hpp and add -include mycast.hpp to your Makefile.
#include <cstdint>
template<typename U, typename T>
U Reinterpret_cast(T *x) {
return (U)(uintptr_t)x;
}
template<typename U, typename T>
U Reinterpret_cast(T &x) {
return *(U*)&x;
}
#define reinterpret_cast Reinterpret_cast
They should do their job unless your code is too tricky.
Your strategy will not work for stack-allocated objects, be careful!! You can insert some debugging/logging logic to Reinterpret_cast if necessary.
I hit this same problem in a project without C++11, and worked around it like this:
inline int PtrToInt(void* ptr)
{
void* clang[1];
clang[0] = ptr;
return *(int*)clang;
}
When I moved a program from a Mac to this Windows PC, the VC++ 2008 compiler is giving me errors for passing unsigned ints to the cmath pow() function. As I understand, this function is not overloaded to accept anything but floating-point numbers.
Is there some compiler flag/setting that will ignore these errors? Also does anyone know how to find the documentation on the VC++ compiler?
Edit
This isn't a warning, it's an error. However, for me it's not an issue since my program is only dealing with numbers that come out as integers, so I don't care that they aren't floats. If it was just warnings I would move on with my life, but it's not letting me compile. Can I suppress errors somehow? Like I said, the errors aren't coming up on my Mac and the program is fine.
Regarding other answers here, it is not a good idea to tell the question author to turn off this warning. His code is broken - he's passing an unsigned int instead of a float. You should be telling him to fix his code!
This isn't a warning, it's an error. However, for me it's not an issue since my
program is only dealing with numbers that come out as integers, so I don't care that
they aren't floats. If it was just warnings I would move on with my life, but it's not
letting me compile. Can I suppress errors somehow? Like I said, the errors aren't
coming up on my Mac and the program is fine.
Integers and floats use different representations internally. If you have the same number in an int and a float, the bit pattern inside the storage for them is completely different. You cannot under any circumstances whatsoever expect your code to work if you are passing an integer when you should be passing a float.
Furthermore, I assert your Mac code either is silently using an overloaded version of that function (e.g. you are on that platform compiling with C++) or you believe it works when in fact it is working by chance or is not actually working.
Addendum
No compilers ever written has the ability to turn off errors.
A warning means the compiler thinks you're making a mistake.
An error means the compiler doesn't know what to do.
There are a couple of options:
In C, the solution is simply to cast the ints to doubles:
pow((double)i, (double)j)
In C++, you can do the same, although you should use a C++-style cast:
pow(static_cast<double>(i), static_cast<double>(j))
But a better idea is to use the overload C++ provides:
std::pow(static_cast<double>(i), j);
The base still has to be a floating-point value, but the exponent can be an int at least
The std:: prefix probably isn't necessary (most compilers make the function available in the global namespace as well).
Of course, to access the C++ versions of the function, you have to include the C++ version of the header.
So instead of #include <math.h> you need to #include <cmath>
C++ provides C++ versions of every C header, using this naming convention. If the C header is called foo.h, the C++ version will be cfoo. When you're writing in C++, you should always prefer these versions.
I don't know of a flag, but getting rid of the warnings was easy enough for me. Just double click on each of the warnings in the "Task List" and add the appropriate casting, whether you prefer
(double) my_variable
or
static_cast<double>(my_variable)
I'm guessing if you're getting the ambiguous warning, there are multiple pow functions defined somewhere. It's better to be explicit in my opinion anyway. For what it's worth, my vote goes with the static_cast option.
As Mehrdad mentioned, use the #pragma warning syntax to disable a warning. Documentation is here - http://msdn.microsoft.com/en-us/library/2c8f766e.aspx
I would be inclined to fix the warnings rather than hide them though!
C++ has overloads for pow/powf for int exponents. Heed the warning.
Don't ignore this or any warnings. Fix them. The compiler is your friend, trying to get you to write good code. It's a friend that believes in tough love, but it is your friend.
If you have an unsigned int and need a float, convert your unsigned in to a float.
And the MSDN Library is the documentation for both the VC++ implementation of the language and the IDE itself.