A
A
Anonymous123443212021-09-26 11:02:20
C++ / C#
Anonymous12344321, 2021-09-26 11:02:20

How to explain this piece of code?

I'm very bad at c++
There is a code snippet:

unsigned long long num = 0xC068C0C000000000;
cout << *(double *) &num;

num in this case is a hexadecimal number, it is converted to a double decimal number on output.
It is not clear to me how such a construction works, i.e. why pass a reference to the num variable?
Why does the following code fragment work incorrectly, for example:
unsigned long long num = 0xC068C0C000000000;
 cout << (double) num;

Answer the question

In order to leave comments, you need to log in

2 answer(s)
E
Evgeny Shatunov, 2021-09-26
@Anonymous12344321

This code demonstrates a typical type punning error (type punning [ ? ]), leading to inevitable UB [ ? ] according to the standard.

num in this case is a hexadecimal number, it is converted to a double decimal number on output.

Here's what the standard says about type substitution.
[ basic.lval#11 ]
If a program attempts to access the stored value of an object through a glvalue whose type is not similar to one of the following types the behavior is undefined:
(11.1) -- the dynamic type of the object,
(11.2) -- a type that is the signed or unsigned type corresponding to the dynamic type of the object, or
(11.3) -- a char, unsigned char, or std​::​byte type.

The relatively unsigned long longtype doubledoes not have any of the properties required by the standard. Hence the direct conclusion that this code contributes UB.
Therefore, the big question remains what is output by this code.
As a result, the correct example of type substitution for another can only be an example where substitution is used for the allowed type of object representation: char, unsigned charor std::bytefor C ++ 17.
The C++ Core Guidelines in section C.183 clearly discourage the use of union. This really should not be done, even if all modern translators understand such constructions in the way the writer suspects.
Why does the following code fragment work incorrectly, for example:

The second block of code means casting a value from type unsigned long longto type double. In this case, it is a standard type conversion that is performed, and not a substitution in order to interpret the memory representation in numa different way.
0xC068C0C000000000for type unsigned long longmeans 13864543383726325760, when this value is converted to type , the doublevalue will be converted to 1.3864543383726326e+19. In this form, it will be displayed.
Regarding the first block of code, the best example of type spoofing for the code in the question would be:
unsigned long long num = 0xC068C0C000000000;
double representation = {};
memcpy( &representation, &num, sizeof( num ) );
cout << representation;

And do not be afraid to contact memcpyhere. This code fully complies with the standard and is expected to be optimized by the compiler to the desired result.
It is not clear to me how such a construction works, i.e. why pass a reference to the num variable?

Sometimes it is required to cast the value type [ ? ], sometimes you need to interpret the memory of this value by another type. This is called type substitution or aliasing. More detailed information about type substitution, and aliasing in general, can be found in this note.

G
galaxy, 2021-09-26
@galaxy

num stores the binary representation of double in IEEE 754 format . The code allows you to forget that this is an int, and interpret this binary data as a double.
Your version will simply translate the unsigned integer num (13864543383726325760) into double (1.3864543383726326e+19)

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question