Reputation: 166086
Context: Established programmer, revisiting C, not for any particular purpose other than better understanding what's really going on behind the scenes.
Consider this program.
#include <stdio.h>
int main()
{
//https://stackoverflow.com/questions/2581769/dereference-a-pointer-inside-a-structure-pointer
int concreteInteger = 42;
int* pointerInteger;
pointerInteger = &concreteInteger;
printf("concreteInteger as %%i = %i\n",concreteInteger);
printf("pointerInteger as %%p = %p\n" ,(void*)pointerInteger);
printf("pointerInteger as %%u = %u\n" ,(unsigned)pointerInteger);
printf("*pointerInteger as %%i = %i\n",*pointerInteger);
printf("Done\n");
return 0;
}
When I compile and run this program on OS X 10.11, I get the following output.
$ cc main.c;./a.out
concreteInteger as %i = 42
pointerInteger as %p = 0x7fff5d614878
pointerInteger as %u = 1566656632
*pointerInteger as %i = 42
Done
Where does 1566656632
come from? If I convert 1566656632
to hex I get 0x5D614878
, not 0x7fff5d614878
.
So where does 1566656632
come from? What incorrect assumption am I making above? Is casting a pointer as an unsigned number something that's undefined in C? If so, for bonus points, if I wanted to represent the hex address of a pointer as a number in base 10, what's the most straight forward way to do that?
Upvotes: 1
Views: 622
Reputation: 166086
I marked the answer above as best because it got me where I needed to be, but the following program gave me what I wanted/needed.
#include <stdio.h>
#include <stdint.h>
//needed for the PRI*PTR Macros
#include <inttypes.h>
int main()
{
//#include <inttypes.h>
int concreteInteger = 42;
int* pointerInteger;
pointerInteger = &concreteInteger;
printf("concreteInteger as %%i = %i\n",concreteInteger);
printf("pointerInteger as %%p = %p\n" ,(void*)pointerInteger);
printf("pointerInteger as %%u = %u\n" ,(unsigned)pointerInteger);
printf("*pointerInteger as %%i = %i\n",*pointerInteger);
//as base 10 printf
printf("pointerInteger as %%lu = %lu\n" ,(uintptr_t)pointerInteger);
printf("pointerInteger as %%llu = %llu\n" ,(unsigned long long)(uintptr_t)pointerInteger);
//as hex printf
printf("pointerInteger as %%lx = %lx\n" ,(uintptr_t)pointerInteger);
printf("pointerInteger as %%llx = %llx\n" ,(unsigned long long)pointerInteger);
//using macros from inttypes.h
printf("pointerInteger as %%PRIxPTR = %" PRIxPTR "\n", (uintptr_t) pointerInteger);
printf("pointerInteger as %%PRIxPTR = %" PRIdPTR "\n", (uintptr_t) pointerInteger);
// 140,734,665,721,976
printf("Done\n");
return 0;
}
A few key things to take away.
stdint.h
library to get the (uintptr_t)
type. %lu
and %lx
were the format strings for displaying a (uintptr_t)
(unsigned long long)
required %llu
and %llx
Upvotes: 0
Reputation: 153592
Conversion of a int*
to void*
does not lose needed information to reference the data as a conversion back to int*
can reference concreteInteger
.
Conversion of OP's int*
to unsigned
(32-bit) retained only 32-bits of the pointer's address.
Try %x
and convert to uintptr_t
first.
uintptr_t
is in C99 and is an optional type, yet very commonly available.
#include <stdint.h>
...
printf("pointerInteger as %%x = %x\n" ,(unsigned)(uintptr_t) pointerInteger);
I'd expect the following, the lower 32-bits of the pointer. @Chris Turner
pointerInteger as %x = 51af8878
Try %llx
and convert to uintptr_t
first to see more.
printf("pointerInteger as %%llx = %llx\n",
(unsigned long long)(uintptr_t) pointerInteger);
With macros in <inttypes.h>
, a matching print specifier can be use to print uintptr_t
types directly.
printf("pointerInteger %" PRIxPTR "\n", (uintptr_t) pointerInteger);
... to represent the hex address of a pointer as a number in base 10, what's the most straight forward way to do that?
The address of a pointer is not "hex", it is what is is. To display a pointer in decimal/hex/octal, convert to a wide enough integer and print using the matching print specifier. To print most portably, convert to void*
and use "%p"
, which may print in hex.
Upvotes: 1