15

I saw this code in project.

b's type is void*:

void *b = ...;
int a = (int) (unsigned long) b;

Is this line pointless? I mean, it this same as a = (int) b in all cases?

Edd
  • 3,724
  • 3
  • 26
  • 33
BufBills
  • 8,005
  • 12
  • 48
  • 90

3 Answers3

25

This probably avoids a compiler warning on 64-bit Unix systems where unsigned long is a 64-bit quantity and hence big enough to hold a pointer, but int is a 32-bit quantity that is not big enough to hold a pointer. The cast to (unsigned long) preserves all the bits of the address; the subsequent cast to int throws away the high-order 32-bits of the address, but does so without getting a warning by default.

To demonstrate:

int main(void)
{
    void *b = (void *)0x12345678;
    int   a = (int)(unsigned long)b;
    int   c = (int)b;
    return a + c;
}

$ gcc -O3 -g -std=c99 -Wall -Wextra -c ar.c
ar.c: In function ‘main’:
ar.c:5:15: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast]
$

Using GCC 4.7.1 on Mac OS X 10.8.4, defaulting to 64-bit compilation.

It is interesting to speculate what will be done with the 'part of an address' value.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
  • 2
    mind you, creative people hide numeric (or boolean) information in `void*`s :) – hroptatyr Jun 18 '13 at 05:28
  • Does that make me creative — with the example code that I was writing while you were commenting? – Jonathan Leffler Jun 18 '13 at 05:29
  • Hehe, indeed it does, hence +1 :) On a serious note, a lot of APIs use `void*` where `intptr_t` would have been appropriate – hroptatyr Jun 18 '13 at 05:31
  • And a lot of APIs use `void *` where the programmers using the API would be better served by an opaque structure type: `extern struct opaque *xyz_create(int); extern void xyz_free(struct opaque *);`. If you replace the `struct opaque` with `void *`, any old pointer can be passed to the `xyz_free()` function, but with the `struct opaque`, you can't pass just any old pointer to it. – Jonathan Leffler Jun 18 '13 at 05:34
  • 1
    +1 for being creative :) One should perhaps mention another problem in the original code, namely that conversion from an unsigned type to a signed type is implementation defined. Also, in your example code you wouldn't need the two casts to `int`. – Jens Gustedt Jun 18 '13 at 05:45
  • @hroptatyr A lot of APIs were defined before `intptr_t` existed. – Jim Balter Jun 18 '13 at 05:49
  • @JensGustedt: You're right that there is another bit of implementation definedness there, but there's also an element of 'why bother about that bit of implementation definedness when the result of truncating an address is also implementation defined'. The idiom is usually symptomatic of problems encountered during the transition from 32-bit to 64-bit coding. Often, there's a function where the original code used `char *` (because it pre-dates `void *`), and back then you could pass integers to the function and not get compiler warnings, but the compilers were updated and the code was not. – Jonathan Leffler Jun 18 '13 at 05:49
1

Directly typecasting to pointer to smaller type say int may result in compilation error on some compiler (like Clang) under x64 bit environment.

For example:

 void *p = GetSomeAddress;
 int i = (int)p;  //error on compilers like Clang.

Solution is:

int i = (int)(unsigned long)p;

or

int i = (int)(long)p;

This is because, on Unix, under LP64 model, long is 64-bit.

Such cases, you need to look thoroughly that why you need typecast from pointer to int or other smaller type which can result in loss of the data.

This question may also help you. How should I handle "cast from ‘void*’ to ‘int’ loses precision" when compiling 32-bit code on 64-bit machine?

Community
  • 1
  • 1
doptimusprime
  • 9,115
  • 6
  • 52
  • 90
0

I see this in my project too.

For my case, the content of 'b' is populated by other sources/middleware used for inter-process communication.

Once 'b' is populated, the program will get the contents of 'b' with a cast to the correct field 'a'. the application then uses 'a' for processing.

My project uses char* instead of void* though.

Angel Koh
  • 12,479
  • 7
  • 64
  • 91