EDIT: Skip down below the horizontal rule for my newest version of the question.
Assuming only that sizeof(double) * CHAR_BITS <= 64, is the assert in following program guaranteed by C++03 to always be satisfied?
union u {
std::int64_t m_int;
double m_double;
};
int main()
{
double d = get_a_random_double();
u u1;
u1.m_double = d;
u u2;
u2.m_int = u1.m_int;
assert(u2.m_double == d);
}
I am worried that it might not be guaranteed by the standard that a copy of an int64_t value preserves all of the bits that we use to hold the double.
On the other hand, I am pretty sure that the following alternative, that uses chars instead of unt64_t, is guaranteed by the standard to always satisfy the assert:
struct chars {
char m_x[sizeof(double)];
};
union u {
chars m_chars;
double m_double;
};
int main()
{
double d = get_a_random_double();
u u1;
u1.m_double = d;
u u2;
u2.m_chars = u1.m_chars;
assert(u2.m_double == d);
}
Do you agree?
EDIT:
Ok, I must concede that conversions by means of a union are not supported by the standard.
So what about this one where I try to transport a double through a sequence of chars without using a union:
int main()
{
double d, e;
char c[sizeof(double)];
char* p_d = static_cast<char*>(static_cast<void*>(&d));
char* p_e = static_cast<char*>(static_cast<void*>(&e));
d = get_a_random_double();
// double -> chars
std::copy(p_d, p_d+sizeof(double), c);
// chars -> double
std::copy(c, c+sizeof(double), p_e);
assert(e == d);
}
Is this one guaranteed by the standard to always satisfy the assert?
EDIT: Yes! See C++11 3.9/2 "Types"
What about this next one where I try to transport the double trough an int64_t without the use of unions.
I know that int64_t is not a part of c++03, so lets talk c++11 instead.
Note again that I am assuming that sizeof(double) * CHAR_BITS <= 64.
int main()
{
double d, e;
std::int64_t i, j;
char c[sizeof(std::int64_t)];
char* p_d = static_cast<char*>(static_cast<void*>(&d));
char* p_e = static_cast<char*>(static_cast<void*>(&e));
char* p_i = static_cast<char*>(static_cast<void*>(&i));
char* p_j = static_cast<char*>(static_cast<void*>(&j));
d = get_a_random_double();
// double -> chars -> std::int64_t
std::copy(p_d, p_d+sizeof(double), c);
std::copy(c, c+sizeof(std::int64_t), p_i);
// std::int64_t -> std::int64_t
j = i; // <------------ Are all bits preserved here?
// std::int64_t -> chars -> double
std::copy(p_j, p_j+sizeof(std::int64_t), c);
std::copy(c, c+sizeof(double), p_e);
assert(e == d);
}
As before, one of my concerns is whether copying one of the standard integers types (std::int64_t) could "corrupt" some bits ( for example, some bits that are not participating in the integer value representation). Or, are integer assignments guaranteed to always faithfully copy all bits of the bytes that the integer occupies?
No, in fact it's undefined behavior:
u u1;
u1.m_double = d;
u u2;
u2.m_int = u1.m_int;
You can't set u1.m_double
and read u1.m_int
.
Only one active union member is allowed at a time.