dpitch40
dpitch40

Reputation: 2691

C compiler relocates pointer that overlaps another variable

I am doing some experiments to see how C allocates variables on the stack. I am getting some odd behavior with the following code. C appears to be growing the stack downward, so in the following example, the char c is allocated in the byte immediately before the short s. I then create an int pointer bigRandP and point it at the same location occupied by c, so the "int" it sees overlaps with the space on the stack occupied by s. I then try to assign something to the location referenced by the int pointer.

unsigned short nameSum = 0;
unsigned char smallRand = 0;
unsigned int* bigRandP;

//The "int" pointed to by iP should overlap s
bigRandP = (unsigned int*)(&smallRand);
printf("%p %p %p\n", &nameSum, &smallRand, bigRandP);
printf("%u %u %u\n", smallRand, nameSum, *bigRandP);
*bigRandP = 0;
printf("%p %p %p\n", &nameSum, &smallRand, bigRandP);
printf("%u %u %u\n", smallRand, nameSum, *bigRandP);

0028FF1A 0028FF19 0028FF19
0 0 419430400
0028FF1A 0028FF19 0028FF00
0 0 4210788

The printed results are interesting. Not only does the assignment fail (the int pointed to by bigRandP is not set to 0), the int pointer itself is silently relocated to point somewhere else further down the stack. What is going on? Is this the C compiler's way of keeping me from overwriting other variables with overlapping pointers?

Upvotes: 0

Views: 194

Answers (1)

Keith Thompson
Keith Thompson

Reputation: 263497

bigRandP is a pointer to unsigned int.

You pointed it to an unsigned char object, then you modified the unsigned int object that bigRandP points to.

Apparently smallRand and bigRandP are stored close to each other in memory. By trying to modify sizeof (unsigned int) bytes of a 1-byte object, you clobbered part of the pointer object itself.

Bottom line: Your program's behavior is undefined.

Also, though this probably isn't related to the behavior you're seeing, the %p format requires a void* argument. If you want to print some other type of pointer, you should convert it to void*:

printf("%p %p %p\n", (void*)&nameSum, (void*)&smallRand, (void*)bigRandP);

It's likely to "work" with or without the casts on systems where all pointers have the same representation, but the version with the casts is more correct on all systems.

Upvotes: 4

Related Questions