Structure memory layout In C

2019-09-08 11:29发布

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?

6条回答
不美不萌又怎样
2楼-- · 2019-09-08 11:54

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.

查看更多
闹够了就滚
3楼-- · 2019-09-08 11:56

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.

查看更多
Fickle 薄情
4楼-- · 2019-09-08 11:59

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;
查看更多
冷血范
5楼-- · 2019-09-08 12:00

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.

查看更多
Summer. ? 凉城
6楼-- · 2019-09-08 12:05

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 *)&pi;

    for (int i = 0; i < 3; i ++) {
        std::cout << i << ": " << items[i] << std::endl;
    }

}
查看更多
别忘想泡老子
7楼-- · 2019-09-08 12:06

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.

查看更多
登录 后发表回答