C++ 相同结构的内存分配

C++ 相同结构的内存分配,c++,pointers,struct,C++,Pointers,Struct,所以我在教我的朋友指针。在这样做时,我注意到两个相同结构的地址完全是背靠背的 struct Foo { int a; }; struct Bar { int b; }; 这让我可以这样做: Foo foo; foo.a = 100; Bar bar; bar.b = 100; Foo *pFoo = &foo; Bar *pBar = &bar; (pFoo+1)->a = 200; 这将覆盖bar.b中的值并将其设置为200 现在,我不是在质疑做

所以我在教我的朋友指针。在这样做时,我注意到两个相同结构的地址完全是背靠背的

struct Foo
{
    int a;
};

struct Bar
{
    int b;
};
这让我可以这样做:

Foo foo; foo.a = 100;
Bar bar; bar.b = 100;

Foo *pFoo = &foo;
Bar *pBar = &bar;

(pFoo+1)->a = 200;
这将覆盖bar.b中的值并将其设置为200


现在,我不是在质疑做这样一件事的好处——它可能永远不会在一个真正的项目中看到光明。我只是想知道,操作系统总是背靠背地分配相同的结构吗?如果给定区域中有足够的可用内存空间。

操作系统不会为局部变量分配堆栈空间,编译器会。C++编译器不能保证分配的顺序。

< P>不,不一定。有些体系结构/编译器可能会对齐边界上的结构,从而使数组中的结构与调用堆栈上的结构之间具有不同的间距。您在调用堆栈上进行分配,并将它们视为连续数组,这是一个不可靠的假设。

否-编译器/链接器通常会将变量放置在完全不同的位置,这些位置与它们在源文件中的位置无关

我很高兴能够使用C代码,这些代码是从到处都是这种假设的汇编语言中翻译出来的(在汇编语言中,当您在同一段/节中有两个相邻的变量时,这就是您将在图中看到的)

那不好玩

请注意,您可能拥有可供使用的工具(例如链接器配置文件或编译器杂注),这些工具可以让您对内存中变量的放置进行一些控制。但在这一点上,您肯定处于“特定于实现”的领域,并且您可能仍然需要处理对齐问题等等(尽管如果结构大小相同,这可能不会成为一个问题)


让两个结构彼此相邻的一种可移植方法是将它们包装到另一个结构中(不过,指针算法和别名可能仍然存在问题)。

不,这不能保证有效

首先也是最重要的是,不相关对象在内存中的位置无法保证。保证对象在内存中连续放置的唯一时间是

  • 如果您自己将它们放在一起(例如,您手动分配一些字节数并将它们一个接一个地放置),或者
  • 如果它们在一个数组中(数组元素总是连续的
因此,以下是有效的:

int ints[2];
*(&ints[0] + 1) = 42;
问题中的代码无效,因为
foo
bar
对象完全不相关,可以放在内存中的任何位置

有一个与此相关的问题,即在结构中可能存在未命名的填充字节

  • 在结构的成员之间(以便成员正确对齐)和
  • 在结构的末尾(以便该结构类型的对象可以连续放置在数组中)
这意味着以下内容无效,因为
Foo
末尾可能有未命名的填充:

Foo foos[2];
*(&foos[0].a + 1) = 42;

作为一项规则,除非两个对象位于一个数组中,否则您永远不应该依赖于它们之间的相对位置。在源代码中,这些对象是相邻声明的,它们具有相同的类型,还是具有相同的大小都无关紧要:根本无法保证。

我记得在使用whOLE程序优化在GCC中,它完全地将所有全局变量重新排序为优化过程的一部分。也就是说,对于C++中的单独变量,这样的布局没有这样的保证。

< P>这不仅仅发生在结构上。单个变量通常是连续的,但正如大家所说的,这不是瓜尔语。anteed(事实上,在我的框中,以下示例的顺序是颠倒的)

结果是

a value: 4 b value: 2 a值:4 b值:2
@SoulBeaver-程序向操作系统请求内存,但它们不会说明内存中发生了什么。因此,操作系统不知道堆栈上是否分配了两个相同的结构。事实上,程序只能请求页面大小块中的空间,而一个页面的长度通常为4096字节,因此两个结构可能都是相同的同时,程序确定内存如何与结构相对应。@DeadMG:是否将“C”更改为“C++”实质上改变了答案的内容?@Omnifarious:事实上,在Windows上,程序可以要求任意多或任意少的内存,因为堆管理器是由操作系统而不是编译器提供的。这是Doug Lea在Unix框和
RtlHeap
在Windows框上使用。@Billy:堆管理器(实际上有几个,一个称为堆管理器,另一个称为分配器,很可能也使用堆)这个问题的代码不使用它,而且可能有99%的代码不存在。C++编译器有自己的堆管理器(在运行时库中),它与Windows分配器有很大的不同,并可能在顶部添加各种调试数据。(顺便说一句,这保证了数据不是“操作系统决定的位置”)@Ben:通常C/C++函数是根据Win32函数实现的。请看:对于背靠背,我不是指源代码中的距离,而是指内存中的距离。如果这取决于源代码的距离,那会很有趣。@SoulBeaver:我知道你想知道结构是否会在内存中相邻,但我想你是在问这是否是由源文件中的位置控制的。你认为还有什么因素可以控制位置?大小、内存碎片、两个大小的划分(可能是 a value: 4 b value: 2