所以我在教我的朋友指点。在这样做时,我注意到两个相同结构的地址完全背靠背。
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.
现在,我并没有质疑做这样事情的优点 - 它可能永远不会在真正的节目中看到光明。我只是想知道,操作系统是否总是背靠背地分配相同的结构?如果在给定区域内有足够的可用内存空间。
答案 0 :(得分:8)
不,不一定。某些体系结构/编译器可能会在边界上对齐结构,使得数组中的结构与调用堆栈上的结构之间存在不同的间距。你在调用堆栈上分配并将它们视为一个连续的数组,这是一个不可靠的假设。
答案 1 :(得分:6)
操作系统不为本地变量分配堆栈空间,编译器会这样做。 C ++编译器不保证分配顺序。
答案 2 :(得分:4)
否 - 编译器/链接器通常会将变量放在与源文件中位置无关的完全不同的位置。
我非常高兴能够使用从汇编转换的C代码,这些代码在整个地方做出了这个假设(在汇编中,当你在同一段/段中有2个变量彼此相邻时,这就是你在图片中得到的结果。)
那不好玩......
请注意,您可以使用工具(例如,链接器配置文件或编译器编译指示),这些工具可以控制内存中变量的位置。但在那时,你肯定处于“特定于实现”的领域,你仍然可能不得不处理对齐问题和诸如此类的问题(尽管结构大小相同,这可能不会成为一个问题)。
将2个结构彼此相邻的可移植方法是将它们包装在另一个结构中(同样,可能仍然存在指针算术和别名问题)。
答案 3 :(得分:4)
不,这不能保证有效。
首先,无法保证在内存中放置不相关的对象。保证对象在内存中连续放置的唯一时间是
因此,以下内容有效:
int ints[2];
*(&ints[0] + 1) = 42;
问题中的代码无效,因为foo
和bar
对象完全不相关,可以放在内存中的任何位置。
有一个相关的问题,在结构中可能有未命名的填充字节
这意味着以下内容无效,因为Foo
末尾可能有未命名的填充:
Foo foos[2];
*(&foos[0].a + 1) = 42;
通常,除非它们在数组中,否则不应该依赖于两个对象相对于彼此的放置。在源代码中对象是否彼此相邻声明,它们具有相同的类型,或者它们具有相同的大小并不重要:根本无法保证。
答案 4 :(得分:1)
我记得在gcc上遇到使用整个程序优化的情况,它在整个优化过程中完全重新排序了所有全局变量。也就是说,对于C ++中的单独变量,这种布局没有这样的保证。
答案 5 :(得分:1)
这不仅仅发生在结构上。个别变量通常是连续的,但正如大家所说的那样,这是不可保证的(实际上,在我的方框中,以下示例的顺序是反转的)
int a,b;
int *pa=&a;
int *pb=&b;
a=1;
b=2;
*(pa)=3;
*(pb+1)=4;
printf("a value: %i \tb value: %i\n", *pa, *pb);
结果是
a value: 4 b value: 2