views:

168

answers:

2

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?

+8  A: 

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).

Len Holgate
@Len Holgate: sizeof `void* = 8, long = 8, int = 4` on the machine I am using.
Amoeba
+3  A: 

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.
Potatoswatter
Seen it in GUI code.
James Morris
+1 for evil alone.
GMan
Or it may not do evil. The `void *` might be an opaque user data item that is being passed through a function to a callback, such as thread start data, for example. It's a `void *` to give the caller the most flexibility. The caller may well pass in an integer value and may well want to get it out on the other side of the call. On Windows you'd probably have the user data as a `ULONG_PTR` these days which would most likely remove the need for the cast to `long`, but you'd still need the cast to `int` and, in this case it's NOT evil but the design could, perhaps, be better.
Len Holgate
@Len: Plausible scenario, although OP specifies it came (somehow) from an iterator. In the interest of extensibility (and portability, as the standard really guarantees nothing in this area), it's usually best to pass a pointer to a structure containing a single integer than to cast the argument to a pointer and back.
Potatoswatter
@Potatoswatter - Agree.
Len Holgate