结构内存布局 在 C 语言中
Structure memory layout In C
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;
到目前为止,我可以理解内存图我感到困惑的是以下代码
((fraction*)&pi.denum)->denum=33;
有没有合法的方法可以打印出那 33 个?任何命令来获取存储在对象视图中的值?
struct fraction
将在内存中作为两个连续ints
进行布局。 您的代码查看表达式 &pi.denum
,它是第二个整数的地址:
-----------------------
| int num | int denum |
-----------------------
^ ^
| |
&pi &(pi.denum)
但是您将&pi.denum
投射到fraction *
并尝试访问((fraction*)&(pi.denum))->num
. 因为num
是struct fraction
的第一个成员,C标准保证它的地址与结构本身相同。 所以
&(((fraction*)&(pi.denum))->num) == (fraction*)&(pi.denum) == &pi.denum.
这是一个有效的内存位置 - 但只是运气好。 如果您尝试访问((fraction*)&(pi.denum))->denom
,则会得到未定义的行为 - 可能会损坏内存或导致分段错误。
最重要的是,((fraction*)&(pi.denum))->num = 12
是无意义的代码。 它永远做不了任何有用的事情。
也许一个简单的图像会有所帮助:
A+0 pi.numA+4 pi.denum
A
是存储在内存中的pi
的基址。 num
存储在地址 A+0
,denum
存储在地址 A+4
(如果int
为 32 位,即 4 字节(。
语句的((fraction*)&(pi.denum))
部分将使布局如下所示:
A+0 pi.numA+4 pi.denum ((fraction*(&(pi.denum((->numA+8 ((分数*(&(pi.denum((->德努姆
如您所见,内存中存在重叠。这意味着语句((fraction*)&(pi.denum))->num=12;
实际上会将pi.num
设置为 12。
此外,如您所见,如果您尝试将((fraction*)&(pi.denum))->denum
设置为一个值,您现在正在分配给pi
结构的内存之外写入,并且可能会覆盖其他变量或其他内容。
首先,如果要打印出 33,则需要使用以下说明:
((fraction*)&pi.denum)->num=33;
现在了解了 C 内存访问机制,结构部分有两个 int 成员。结构的基址指向第一个元素地址。
&pi.denum 现在给出第二个元素地址,将其强制转换为结构指针,以便它在逻辑上将 denum 地址视为 num 地址,但在物理上将其视为 denim 地址。
因此,如果要更改牛仔布值,则必须使用指向牛仔布地址的第一个元素地址。
该行可能会将 pi.denum 设置为 12,但它是未定义的行为。成员 "num" (在大多数情况下(位于结构的开头,因此something.num
就像 (int)something
一样(当然,这个something
必须是分数(,但您不应该假设它可以在每台机器上工作。
如果这段代码基本上是错误的,也许你正在搜索这个:
#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;
}
}
在您的问题中发布的代码中,您已经告诉编译器表现得好像pi.denum
的地址实际上是fraction struct
的地址。
它不是,因此您靠自己获得正确的内存寻址。 C(或 C++(将按照您指定的顺序在内存中布置您的结构,仅受对齐填充的限制。
因此,在具有 32 位整数和 32 位整数的典型 32 位对齐方式的计算机上,您的行((fraction*)&(pi.denum))->num=12;
将pi.denum
设置为 12,而不是pi.num
。 ->num
是指针的偏移量(偏移量为零(,指针指向pi.denum
,因此设置的是pi.denum
。
这不会崩溃,因为您只是使用了一个特殊的表达式来寻址堆栈上正确分配的内存。
下面的代码((fraction*)&pi.denum)->denum=33;
将写入分配pi
之外的内存。 这是崩溃还是简单地覆盖另一个变量取决于您在堆栈上分配的其他内容,也可能取决于您的编译器和编译器设置。
如果你真的想在结构后面的内存上涂鸦,然后读回它,同样的寻址表达式会为你做,例如
int myTest = ((fraction*)&pi.denum)->denum;
- 将字符串存储在c++中的稳定内存中
- C++ 指针的内存地址和指向数组的内存地址如何相同?
- Win32编译器选项和内存分配
- 当vector是tje全局变量时,c++中vector的内存管理
- 在闭包中,如何通过存储在内存中的指针或引用类型捕获可变性或用现代函数式语言进行处理?
- 如何从C或C 语言级别安全访问内存映射的硬件寄存器
- 是否所有面向对象的语言都会在内存中创建大量重复信息
- 如何在运行时用C语言查看程序的内存布局
- C++/C语言无关的内存分配
- C 语言中的多个内存地址
- 是任何编程语言(C++、C#、Java、C.)中声明函数的最终内存地址,无论是相对地址还是绝对地址
- 编程语言函数在内存中的位置
- 用另一种语言包装C++对象的策略——内存管理
- 如何在c语言中清除内存
- 使用.net或任何其他语言在内存中进行ghostscript转换
- 跨语言的内存存储
- 在大量使用unique_ptr语言 - c++后释放内存给操作系统
- c语言如何分配内存给常量字符串
- 复杂语言中类型的内存管理
- GMP,C语言内存分配和指针