C++ code is known for being easy to break without noting.
There are lots of examples of undefined behavior (like i = i++ and many more, e.g. in Why are these constructs using pre and post-increment undefined behavior?). Most of them are easy to spot since they usually involve a combination of pre-/post- increments on the same variable and/or sensitive to the summation order.
Here is yet another example, which almost looks like right:
#include <iostream>
int main()
{
float a[] = {1.f, 2.f, 3.f};
float* b = a;
float c = pow(*b++, 2) + pow(*b++, 2);
std::cout << c << "," << *b;
}
At the first glance, it doesn't matter which one of pow(*b++, 2)
terms
will be execute first.
Nevertheless, it prints out "5,3" when compiled and ran in Debug mode (standard Visual Studio console C++ project, all defaults) and prints out "2,3" when doing so in Release mode (tested with both VS2008 and VS2019).
It is straightforward to spot different order of operations produced by the compiler when dealing with the * and ++ operator at the same time.
Without being optimized in Debug mode, the expression pow(*b++, 2) + pow(*b++, 2)
is equivalent to:
float c;
c = pow(*b, 2);
b++;
c+= pow(*b, 2);
b++;
Withe the Release optimizations turned on, it behaves like this:
float c;
c = pow(*b, 2);
c+= pow(*b, 2);
b++;
b++;
Considering the example above and alike, my questions are:
Is there any compiler setting/warning to detect such situations?
If it can't be detected during the compilation, what are the standard Visual Studio tools for dealing with such cases? [I'm looking for the primarily integrated VS-solution, aside from standalone linters]