Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What does this C++ construct do?

Tags:

c++

casting

Somewhere in lines of code, I came across this construct...

//void* v = void* value from an iterator
int i = (int)(long(v))

What possible purpose can this contruct serve?

Why not simply use int(v) instead? Why the cast to long first?

like image 797
Moeb Avatar asked Mar 22 '26 14:03

Moeb


2 Answers

It most possibly silences warnings.

Assuming a 32bit architecture with sizeof(int) < sizeof(long) and sizeof(long) == sizeof(void *) you possibly get a warning if you cast a void * to an int and no warning if you cast a void * to a long as you're not truncating. You then get a warning assigning a long to an int (possible truncation) which is removed by then explicitly casting from a long to an int.

Without knowing the compiler it's hard to say, but I've certainly seen multi-step casts required to prevent warnings. Why not try converting the construct to what you think it should be and see what the compiler says (of course that only helps you to work out what was in the mind of the original programmer if you're using the same compiler and same warning level as they were).

like image 139
Len Holgate Avatar answered Mar 25 '26 04:03

Len Holgate


It does eeevil.

On most architectures, a pointer can be considered to be just another kind of number. On most architectures, long is as many bits as a pointer, so there is a 1-to-1 map between long values and pointers. But violations, especially of the second rule, are not uncommon!

long(v) is an alias for reinterpret_cast<long>(v), which carries no guarantees. Not really fit for any purpose, unless your ABI spec says otherwise.

However, for whatever reason, whoever wrote that code prefers int to long. So they again cross their fingers and hope that no essential information is thrown out in the bits that may possibly be lost in the int to long cast.

Two uses of this are creating a unique object identifier, or trying to somehow package the pointer for some kind of arithmetic otherwise unsupported by pointers.

  • An opaque identifier can be a void*, so casting to integral type is unnecessary.
  • "Extracting" an integer from a pointer (for e.g. a division operation) can always be done by subtracting a base pointer to obtain a difference of type ptrdiff_t, which is usually long.
like image 38
Potatoswatter Avatar answered Mar 25 '26 03:03

Potatoswatter



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!