I've come across this behavior of std::gcd that I found unexpected:
#include <iostream>
#include <numeric>
int main()
{
int a = -120;
unsigned b = 10;
//both a and b are representable in type C
using C = std::common_type<decltype(a), decltype(b)>::type;
C ca = std::abs(a);
C cb = b;
std::cout << a << ' ' << ca << '\n';
std::cout << b << ' ' << cb << '\n';
//first one should equal second one, but doesn't
std::cout << std::gcd(a, b) << std::endl;
std::cout << std::gcd(std::abs(a), b) << std::endl;
}
Run on compiler explorer
According to cppreference both calls to std::gcd should yield 10, as all preconditions are satisfied.
In particular, it is only required that the absolute values of both operands are representable in their common type:
If either |m| or |n| is not representable as a value of type std::common_type_t<M, N>, the behavior is undefined.
Yet the first call returns 2.
Am I missing something here?
Both gcc and clang behave this way.
Looks like a bug in libstc++. If you add -stdlib=libc++ to the CE command line, you'll get:
-120 120
10 10
10
10
Related
Code:
#include <iostream>
int main() {
int a = 137;
const int &b = a;
std::cout << a << " " << b << std::endl; // prints 137 137
a++;
std::cout << a << " " << b << std::endl; // prints 138 138
}
The value of variable b becomes 138 after a++ statement, although it's declared as const Shouldn't this be not allowed? how to make sure this won't happen? or at least get a warning for doing that.
I am using GNU GCC Compiler
Shouldn't this be not allowed?
It's fine. Your code only prevents the b reference from changing the value, but the original variable a doesn't have such a restriction, so it can be freely changed.
What's the C++ rules that means equal is false?. Given:
float f {-1.0};
bool equal = (static_cast<unsigned>(f) == static_cast<unsigned>(-1.0));
E.g. https://godbolt.org/z/fcmx2P
#include <iostream>
int main()
{
float f {-1.0};
const float cf {-1.0};
std::cout << std::hex;
std::cout << " f" << "=" << static_cast<unsigned>(f) << '\n';
std::cout << "cf" << "=" << static_cast<unsigned>(cf) << '\n';
return 0;
}
Produces the following output:
f=ffffffff
cf=0
The behaviour of your program is undefined: the C++ standard does not define the conversion of a negative floating point type to an unsigned type.
(Note the familiar wrap-around behaviour only applies to negative integral types.)
So therefore there's little point in attempting to explain your program output.
Pretty basic code:
#include <iostream>
int main() {
std::cout.precision(100);
double a = 9.79999999999063220457173883914947509765625;
double b = 0.057762265046662104872599030613855575211346149444580078125;
const double bConst = 0.057762265046662104872599030613855575211346149444580078125;
double c = a * b;
std::cout << " a: " << a << std::endl;
std::cout << " b: " << b << std::endl;
std::cout << " bConst: " << bConst << std::endl;
std::cout << " c: " << c << std::endl << std::endl;
std::cout << " c/b: " << c / b << std::endl;
std::cout << " c/bConst: " << c / bConst << std::endl;
}
Which outputs:
a: 9.79999999999063220457173883914947509765625
b: 0.057762265046662104872599030613855575211346149444580078125
bConst: 0.057762265046662104872599030613855575211346149444580078125
c: 0.5660701974567474703547986791818402707576751708984375
c/b: 9.7999999999906304282148994388990104198455810546875
c/bConst: 9.79999999999063220457173883914947509765625
As you can see, b and bConst seem to be treated using the same value - i.e. it prints for both the same 0.057762265046662104872599030613855575211346149444580078125 value.
So I guess they are "stored" both the same. The only difference is that b is not const.
Then, I do the same c / b operation twice: one time using b, another time using bConst.
As you can see, it leads to two different results. And this makes me wonder.
Can you explain technically why this happens?
The "issue" is due to the -freciprocal-math switch (implied by -Ofast):
Allow the reciprocal of a value to be used instead of dividing by the value if this enables optimizations. For example x / y can be replaced with x * (1/y), which is useful if (1/y) is subject to common subexpression elimination. Note that this loses precision and increases the number of flops operating on the value.
The compiler can calculate d = 1/bConst at compile time and change from:
c/bConst
to
c * d
but multiplication and division are different instructions with different performance and precision.
See: http://coliru.stacked-crooked.com/a/ba9770ec39ec5ac2
You are using -Ofast in your link, which enables all -O3 optimizations and includes both -ffast-math, which in turns includes -funsafe-math-optimizations.
From what I could glean, with optimizations enabled, -funsafe-math-optimizations allows the compiler to reduce the precision of some computations. This seems to be what happens in the c/bConst case.
The following code gives different results with the g++ 7 compiler and Apple clang++. Did I run into a bug in clang in the alignment of bool output when std::boolalpha is used, or did I make a mistake?
#include <string>
#include <sstream>
#include <iostream>
#include <iomanip>
template<typename T>
void print_item(std::string name, T& item) {
std::ostringstream ss;
ss << std::left << std::setw(30) << name << "= "
<< std::right << std::setw(11) << std::setprecision(5)
<< std::boolalpha << item << " (blabla)" << std::endl;
std::cout << ss.str();
}
int main() {
int i = 34;
std::string s = "Hello!";
double d = 2.;
bool b = true;
print_item("i", i);
print_item("s", s);
print_item("d", d);
print_item("b", b);
return 0;
}
The difference is:
// output from g++ version 7.2
i = 34 (blabla)
s = Hello! (blabla)
d = 2 (blabla)
b = true (blabla)
// output from Apple clang++ 8.0.0
i = 34 (blabla)
s = Hello! (blabla)
d = 2 (blabla)
b = true (blabla)
At T.C. mentioned, this is LWG 2703:
No provision for fill-padding when boolalpha is set
N4582 subclause 25.4.2.2.2 [facet.num.put.virtuals] paragraph 6 makes
no provision for fill-padding in its specification of the behaviour
when (str.flags() & ios_base::boolalpha) != 0.
As a result I do not see a solution to this with Clang. However, notice that:
libc++ implements this exactly.
libstdc++ and MSVC apply padding and alignment.
PS: LWG stands for Library Working Group.
The following code is, as far as I understand it, undefined behavior according to the c++ standard (section 7.1.5.1.4 [dcl.type.cv]/4 in particular).
#include <iostream>
struct F;
F* g;
struct F {
F() : val(5)
{
g = this;
}
int val;
};
const F f;
int main() {
g->val = 8;
std::cout << f.val << std::endl;
}
However, this prints '8' with every compiler and optimization setting I have tried.
Question: Is there an example that will exhibit unexpected results with this type of "implicit const_cast"?
I am hoping for something as spectacular as the results of
#include <iostream>
int main() {
for (int i = 0; i <=4; ++i)
std::cout << i * 1000000000 << std::endl;
}
on, e.g., gcc 4.8.5 with -O2
EDIT: the relevant section from the standard
7.1.5.1.4: Except that any class member declared mutable (7.1.1) can be modified, any attempt to modify a const object during its lifetime
(3.8) results in undefined behavior.
In reply to the comment suggesting a duplicate; it is not a duplicate because I am asking for an example where "unexpected" results occur.
Not as spectacular:
f.h (guards omitted):
struct F;
extern F* g;
struct F {
F() : val(5)
{
g = this;
}
int val;
};
extern const F f;
void h();
TU1:
#include "f.h"
// definitions
F* g;
const F f;
void h() {}
TU2:
#include "f.h"
#include <iostream>
int main() {
h(); // ensure that globals have been initialized
int val = f.val;
g->val = 8;
std::cout << (f.val == val) << '\n';
}
Prints 1 when compiled with g++ -O2, and 0 when compiled with -O0.
The main case of "undefined" behavior would be that typically, if someone sees const, they will assume that it does not change. So, const_cast intentionally does something that many libraries and programs would either not expect to be done or consider as explicit undefined behavior. It's important to remember that not all undefined behavior comes from the standard alone, even if that is the typical usage of the term.
That said, I was able to locate a place in the standard library where such thinking can be applied to do something I believe would more narrowly be considered undefined behavior: generating an std::map with "duplicate keys":
#include "iostream"
#include "map"
int main( )
{
std::map< int, int > aMap;
aMap[ 10 ] = 1;
aMap[ 20 ] = 2;
*const_cast< int* >( &aMap.find( 10 )->first ) = 20;
std::cout << "Iteration:" << std::endl;
for( std::map< int,int >::iterator i = aMap.begin(); i != aMap.end(); ++i )
std::cout << i->first << " : " << i->second << std::endl;
std::cout << std::endl << "Subscript Access:" << std::endl;
std::cout << "aMap[ 10 ]" << " : " << aMap[ 10 ] << std::endl;
std::cout << "aMap[ 20 ]" << " : " << aMap[ 20 ] << std::endl;
std::cout << std::endl << "Iteration:" << std::endl;
for( std::map< int,int >::iterator i = aMap.begin(); i != aMap.end(); ++i )
std::cout << i->first << " : " << i->second << std::endl;
}
The output is:
Iteration:
20 : 1
20 : 2
Subscript Access:
aMap[ 10 ] : 0
aMap[ 20 ] : 1
Iteration:
10 : 0
20 : 1
20 : 2
Built with g++.exe (Rev5, Built by MSYS2 project) 5.3.0.
Obviously, there is a mismatch between the access keys and the key values in the stored pairs. It also seems that the 20:2 pair is not accessible except via iteration.
My guess is that this is happening because map is implemented as a tree. Changing the value leaves it where it initially was (where 10 would go), so it does not overwrite the other 20 key. At the same time, adding an actual 10 does not overwrite the old 10 because on checking the key value, it's not actually the same
I do not have a standard to look at right now, but I would expect this violates the definition of map on a few levels.
It might also lead to worse behavior, but with my compiler/OS combo I was unable to get it to do anything more extreme, like crash.