开发者

C pointer conversion rules

I have the following code:

#include <stdio.h>
#include <stdlib.h>

typedef union stateof stateof;
union stateof 
{
  stateof* foo;
  double* bar;
};

typedef struct hunch hunch;
struct hunch{
  double* first;
  double* second;
};

void main(){
  #define write(x) printf("%d \n",x);

  int* storage = 0;
  stateof* un = (stateof*)&storage;
  un->foo = 300;
  write(storage);

  un->bar = 600;
  write(storage);

  hunc开发者_运维问答h* h = (hunch*)&storage;
  h->first = 1200;
  write(storage);

  h->second = 1600;
  write(storage);
}

The output of this program is:

300   
600   
1200   
1200

What is happening here?

What does it mean for the un->{foo,bar} and h->{first,second} statements to execute when they most definitely do not point to valid structures? What is exactly occurring during this period and why is the output of the union different than that of the structure?


Your program causes all kinds of undefined behaviour. You could get any kind of output imaginable. Your compiler is probably giving you all kinds of warnings when you compile this code - try fixing those up and you should be headed in a better direction.

Assuming you have a normal sort of system, the reason you're getting the output you see can be explained:

  1. modifying un->foo overwrites storage with the value 300 - then you print it out.
  2. modifying un->bar overwrites storage with the value 600 - then you print it out.
  3. modifying h->first overwrites storage with the value 1200 - then you print it out.
  4. modifying h->second (DANGEROUSLY) overwrites some memory with the value 1600, then you print out storage again - it's still 1200.


I'll describe all in details.

int* storage = 0; - creates a Pointer on the stack with zero value (points to NULL in other words).

stateof* un = (stateof*)&storage; - un points to the location of storage which is a pointer. So un points to the storage's value which is now equals 0.

un->foo = 300; - assigns 300 into storage (lets think about storage like about some int value because it doesn't matter that it is a pointer in fact here), so storage == 300 now.

un->bar = 600; - the same as the previous, because un is a union and all its fields in fact just different names for only one field (well, its union's definition).

h->first = 1200; and h->second = 1600; are like the previous cases with only one exception that here values are assigned to DIFFERENT fields in the struct (different places in memory).

write(storage); - printing the value of storage (which is a pointer) but not the value where storage points to (*storage).

And of course, the last but not the least: NEVER CODE LIKE THAT ANYMORE! :)


We don't know what will happen. The language standard doesn't say.

When you write a program, there is an implied contract between you and the compiler. If you write a correct program, it has to produce an executable that does exactly what the source code said.

When you use code like

stateof* un = (stateof*)&storage;

you are telling the compiler "I know for sure that &storage actually points to a stateof union. Trust me, I know what I am doing!".

And the compiler thinks "If you say so...", and acts accordingly. But as you have then broken the contract, it is free to do just about anything. We just don't know what the output could be, or if there would even be one.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜