C++ C语言中的结构内存布局

C++ C语言中的结构内存布局,c++,memory,pointers,struct,C++,Memory,Pointers,Struct,有没有合法的方法把那33页打印出来?? 获取不在对象视图中的存储值的任何命令?如果要打印33,首先需要使用以下指令: ((fraction*)&pi.denum)->denum=33; 现在了解C内存访问机制,结构部分有两个int成员。 结构的基址指向第一个元素地址 &pi.denum现在将第二个元素地址转换为结构指针,这样它在逻辑上将denum地址视为num地址,但在物理上将其视为denim地址 因此,如果要更改牛仔值,必须使用指向牛仔地址的第一个元素地址。该行可能会将pi.d

有没有合法的方法把那33页打印出来??
获取不在对象视图中的存储值的任何命令?

如果要打印33,首先需要使用以下指令:

((fraction*)&pi.denum)->denum=33;
现在了解C内存访问机制,结构部分有两个int成员。 结构的基址指向第一个元素地址

&pi.denum现在将第二个元素地址转换为结构指针,这样它在逻辑上将denum地址视为num地址,但在物理上将其视为denim地址


因此,如果要更改牛仔值,必须使用指向牛仔地址的第一个元素地址。

该行可能会将pi.denum设置为12,但这是未定义的行为。
成员“num”(在大多数情况下)位于结构的开头,因此
something.num
类似于
(int)something
(当然,这个
something
必须是一个分数),但是您不应该假设它在每台机器上都能工作。

一个
结构分数将作为两个连续的
整数在内存中显示。代码查看表达式
&pi.denum
,它是第二个整数的地址:

((fraction*)&pi.denum)->num=33;
但是您将
&pi.denum
转换为
分数*
,并尝试访问
((分数*)和(pi.denum))->num
。由于
num
struct fraction
的第一个成员,因此C标准保证其地址与结构本身相同。所以

 -----------------------   
|  int num  | int denum |
 -----------------------
 ^           ^
 |           |
 &pi         &(pi.denum)
是一个有效的内存位置,但只能靠运气。如果您试图访问
((分数*)&(pi.denum))->denom
,您将得到未定义的行为-可能会损坏内存或导致分段错误


底线是,
((分数*)和(π.密度))->num=12
是无意义的代码。它永远不会做任何有用的事情。

也许一个简单的图像会有帮助:

&(((fraction*)&(pi.denum))->num) == (fraction*)&(pi.denum) == &pi.denum.
正如您所看到的,内存中存在重叠。这意味着语句
((分数*)&(pi.denum))->num=12
将实际将pi.num设置为12


同样,如您所见,如果您试图将
((分数*)&(pi.denum))->denum
设置为一个值,您现在正在分配给
pi
结构的内存之外写入,并且可能会覆盖其他变量或其他内容。

如果此代码基本上是错误的,那么您可能正在搜索以下内容:

A+0 pi.num A+4 pi.denum ((fraction*)&(pi.denum))->num A+8 ((fraction*)&(pi.denum))->denum
#包括
int main(){
结构分数{
int-num;
内密度;
}pi;
pi.num=22;
pi.密度=7;
((分数*)和(π密度))->num=12;

std::cout在您问题中发布的代码中,您已告诉编译器将
pi.denum
的地址视为
分数结构的地址

事实并非如此,因此您需要自行确定内存地址。C(或C++)将按照您指定的顺序在内存中布局结构,只需填充对齐即可

因此,在具有32位整数和32位整数的典型32位对齐的机器上,您的行
((分数*)&(pi.denum))->num=12;
pi.denum
设置为12,而不是
pi.num
->num
是指针的偏移量(偏移量为零)指针指向
pi.denum
,所以设置的是
pi.denum

这不会崩溃,因为您只是使用了一个特殊的表达式来寻址堆栈上正确分配的内存

以下代码
((分数*)&pi.denum)->denum=33;
将在
pi
的分配之外写入内存。这是崩溃还是仅仅覆盖另一个变量取决于您在堆栈上分配的其他变量,可能还取决于您的编译器和编译器设置

如果您真的想在结构后面的内存上涂鸦,然后将其读回,那么同样的寻址表达式也可以为您实现,例如

#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;
    }

}

请…下次设置代码格式。我尽了最大努力设置代码的格式,但代码没有多大意义(您可能会用该代码覆盖堆栈上的其他内容,这可能会使其稍后崩溃)。您试图完成的是什么?行((分数*)&pi.denum)->denum=33;
有未定义的行为,因此在那之后没有“合法”的方法来做任何事情。我可能是一个多愁善感的夜猫子,害怕女人,但我从来没有考虑过诱惑指针……这是定义的行为。指向结构的指针,转换为第一个成员的类型,将是指向该成员的指针(但这只适用于第一个成员)。
((分数*)&(pi.denum))->denom
只会在幸运的情况下产生segfault,通常它只是UB,可能是segfault,也可能覆盖完全不相关的内容(如果在那里分配了
pi
,可能会损坏堆,或者在其他地方覆盖指针,因此它可能在代码中完全不相关的位置发生故障(对于给定的代码示例,它可能不会执行任何操作)) A+0 pi.num A+4 pi.denum ((fraction*)&(pi.denum))->num A+8 ((fraction*)&(pi.denum))->denum
#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;
    }

}
int myTest = ((fraction*)&pi.denum)->denum;