可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
struct fraction {
int num;
int denum;
} pi;
pi.num=22;
pi.denum=7;
((fraction*)&(pi.denum))->num=12;
cout << endl;
cout << pi.denum <<endl;
cout << pi.num <<endl;
I can understand the memory diagram till this point
What I have confusion is is the following code
((fraction*)&pi.denum)->denum=33;
Is there a legal way to get that 33 printed out ??
ANY command to get the value stored which is not in the view of an object?
回答1:
A struct fraction
will be layed out in memory as two consecutive ints
. Your code looks at the expression &pi.denum
, which is the address of the second integer:
-----------------------
| int num | int denum |
-----------------------
^ ^
| |
&pi &(pi.denum)
But you cast &pi.denum
to a fraction *
and try to access ((fraction*)&(pi.denum))->num
. Since num
is the first member of struct fraction
, the C standard guarantees that its address is the same as the struct itself. So
&(((fraction*)&(pi.denum))->num) == (fraction*)&(pi.denum) == &pi.denum.
It is a valid memory location - but only by luck. If you tried to access ((fraction*)&(pi.denum))->denom
, you'd get undefined behavior - possibly corrupting memory or causing a segmentation fault.
Bottom line, ((fraction*)&(pi.denum))->num = 12
is nonsense code. It could never do anything useful.
回答2:
Maybe a simple image will help:
A+0 pi.num
A+4 pi.denum
A
is the base address where pi
is stored in memory. num
is stored at address A+0
and denum
is stored at address A+4
(if an int
is 32 bits, i.e. 4 bytes).
The ((fraction*)&(pi.denum))
part of the statement will make the layout look something like this:
A+0 pi.num
A+4 pi.denum ((fraction*)&(pi.denum))->num
A+8 ((fraction*)&(pi.denum))->denum
As you can see there is an overlap in memory. This means that the statement ((fraction*)&(pi.denum))->num=12;
will actually set pi.num
to 12.
Also as you can see, if you try to set ((fraction*)&(pi.denum))->denum
to a value, you are now writing outside of the memory allocated to the pi
structure, and may overwrite other variables or other things.
回答3:
First if you want to print out the 33 than you need to use following instruction:
((fraction*)&pi.denum)->num=33;
Now understand the C memory access mechanisum the struct fraction have two int member.
The base address of struct point to first element address.
&pi.denum give the second element address now you cast it to the struct pointer so it treat the denum address as num address logically but physically it denim address.
So if you want to change the denim value you have to use the first element address which point to denim address.
回答4:
That line probably will set pi.denum to 12, but it's undefined behavior.
The member "num" is (in most cases) in the beginning of the struct, so something.num
is like (int)something
(of course, this something
must be a fraction), but you should not assume that it will work on every machine.
回答5:
Provided that this code is basically wrong, maybe you are searching for this:
#include <iostream>
int main () {
struct fraction {
int num;
int denum;
} pi;
pi.num=22;
pi.denum=7;
((fraction*)&(pi.denum))->num=12;
std::cout << std::endl;
std::cout << pi.denum <<std::endl;
std::cout << pi.num <<std::endl;
((fraction*)&pi.denum)->denum=33;
int * items;
items = (int *)π
for (int i = 0; i < 3; i ++) {
std::cout << i << ": " << items[i] << std::endl;
}
}
回答6:
In the code posted in your question, you have told the compiler to act as if the address of pi.denum
is actually the address of a fraction struct
.
It is not, and therefore you are on your own in getting the memory addressing right. C (or C++) will lay out your struct in memory in the order you specify, subject only to padding for alignment.
So, on a machine with 32-bit ints and typical 32-bit alignment for 32-bit ints, your line ((fraction*)&(pi.denum))->num=12;
will set pi.denum
to 12, not pi.num
. The ->num
is an offset from a pointer (the offset is zero) and your pointer is to pi.denum
, so it is pi.denum
that gets set.
This will not crash, because you have simply used a peculiar expression to address memory that is properly allocated on your stack.
The following code ((fraction*)&pi.denum)->denum=33;
will write to memory outside of the allocation of pi
. Whether this crashes or simply overwrites another variable depends on what else you have allocated on the stack and perhaps on your compiler and compiler settings.
If you actually want to scribble on the memory that follows your struct and then read it back, the same addressing expression will do it for you, e.g.
int myTest = ((fraction*)&pi.denum)->denum;