Reputation: 93
Here is my code
struct ukai { int val[1]; };
struct kai { struct ukai daddr; struct ukai saddr; };
struct kai *k, uk;
uk.saddr.val[0] = 5;
k = &uk;
k->saddr.val[0] = 6;
unsigned int *p = (unsigned int *)malloc(sizeof(unsigned int));
p[0] = k;
int *vp;
vp = ((uint8_t *)p[0] + 4);
printf("%d\n", *vp);
This produces a segmentation fault. However if we replace the last line with printf("%u\n", vp)
it gives the address i.e. &(k->saddr.val[0])
. However I am unable to print the value present at the address using p[0]
but able to print it using k->saddr.val[0]
.
I have to use p
pointer in some way to access value at val[0]
, I can't use pointer k
. I need help here, whether it is even possible or not please let me know.
Upvotes: 1
Views: 90
Reputation: 6875
There is a lot of "dirty" mess with the addresses done here. Some of this stuff is not recommended or even forbidden from the standard C point of view.
However such pointer/addresses tweaks are commonly used in low level programming (embedded, firmware, etc.) when some compiler implementation details are known to the user. Of course such code is not portable.
Anyway the issue here (after getting more details in the comments section) is that the machine on which this code runs is 64 bits. Thus the pointers are 64 bits width while int
or unsigned int
is 32 bits width.
So when storing address of k
in p[0]
p[0] = k;
while p[0]
is of type unsigned int
and k
is of type pointer to struct kai
, the upper 32 bits of the k
value are cut off.
To resolve this issue, the best way is to use uintptr_t
as this type will alway have the proper width to hold the full address value.
uintptr_t *p = malloc(sizeof(uintptr_t));
Note: uintptr_t
is optional, yet common. It is sufficient for a void*
, but maybe not a function pointer. For compatible code, proper usage of uintptr_t
includes object pointer --> void *
--> uintptr_t
--> void *
--> object pointer.
Upvotes: 0
Reputation: 144695
The code makes no sense:
p[0] = k;
converts the value of a pointer k
to an int
as p
is a pointer to int
. This is implementation defined and loses information if pointers are larger than type int
.vp = ((uint8_t *)p[0] + 4);
converts the int
pointed to by p
to a pointer to unsigned char and makes vp
point to the location 4 bytes beyond this pointer. If pointers are larger than int
, this has undefined behavior. Just printing the the value of this bogus pointer might be OK, but dereferencing it has undefined behavior.printf("%u\n", vp)
uses an incorrect format for pointer vp
, again this is undefined behavior, although it is unlikely to crash.The problem is most likely related to the size of pointers and integers: if you compile this code as 64 bits, pointers are larger than ints, so converting one to the other loses information.
Here is a corrected version:
struct ukai { int val[1]; };
struct kai { struct ukai daddr; struct ukai saddr; };
struct kai *k, uk;
uk.saddr.val[0] = 5;
k = &uk;
k->saddr.val[0] = 6;
int **p = malloc(sizeof *p);
p[0] = k;
int *vp = (int *)((uint8_t *)p[0] + sizeof(int));
printf("%d\n", *vp); // should print 6
Upvotes: 3