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:
- modifying
un->foo
overwritesstorage
with the value300
- then you print it out. - modifying
un->bar
overwritesstorage
with the value600
- then you print it out. - modifying
h->first
overwritesstorage
with the value1200
- then you print it out. - modifying
h->second
(DANGEROUSLY) overwrites some memory with the value1600
, then you print outstorage
again - it's still1200
.
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.
精彩评论