So I was teaching my friend about pointers. While doing so, I noticed that the address of two identical structs are exactly back-to-back.
struct Foo
{
int a;
};
struct Bar
{
int b;
};
Which allowed me to do this:
Foo foo; foo.a = 100;
Bar bar; bar.b = 100;
Foo *pFoo = &foo;
Bar *pBar = &bar;
(pFoo+1)->a = 200;
This overrides the value in bar.b and sets it to 200.
Now, I'm not questioning the merits of doing such a thing- it will probably never see the light of day in a real program. I was just wondering, do开发者_如何学JAVAes the OS always allocate identical structs back-to-back? Provided there is enough memory space free in the given area.
No, not necessarily. It is possible that some architectures/compilers will align structures on boundaries such that there are different spacings between structs in an array and structs on the call stack. You're allocating on the call stack and treating them as a contiguous array, that's an unreliable assumption.
The operating system doesn't allocate stack space for local variables, the compiler does. C++ compilers don't guarantee the order of allocation.
No - quite often the compiler/linker will place variables in wildly different locations that bear no relation to their location in the source files.
I've had the distinct pleasure to have to work with C code that was translated from assembly that made this assumption all over the place (in assembly, when you have 2 variables next to each other in the same segment/section, that's what you'll get in the image).
That wasn't fun...
Note that you may have tools at your disposal (linker config files or compiler pragmas, for example) that might give you some control over the placement of variables in memory. But at that point, you're decidedly in 'implementation specific' territory, and you still might have to deal with alignment issues and whatnot (though if the structs are the same size, that's probably not going to be a concern).
A portable way to have 2 structs adjacent to one another is to wrap them inside another struct (again, there might still be issues with pointer arithmetic and aliasing, though).
No, this is not guaranteed to work.
First and foremost, there is no guarantee on the placement of unrelated objects in memory. The only times that objects are guaranteed to be placed contiguously in memory are
- if you put them next to each other yourself (e.g., you manually allocate some number of bytes and place them one after the other) or
- if they are in an array (array elements are always contiguous
So, the following is valid:
int ints[2];
*(&ints[0] + 1) = 42;
The code in the question is not valid because the foo
and bar
objects are entirely unrelated and could be placed anywhere in memory.
There is a somewhat related issue that within a struct there may be unnamed padding bytes either
- between members of the struct (so that members are correctly aligned) and
- at the end of the struct (so that objects of that struct type can be placed contiguously in an array)
This means that the following is not valid because there could be unnamed padding at the end of a Foo
:
Foo foos[2];
*(&foos[0].a + 1) = 42;
As a rule, you should never rely on the placement of two objects relative to each other unless they are in an array. It doesn't matter whether the objects are declared next to each other in the source code, they have the same type, or they have the same size: there simply is no guarantee.
I remember encountering a situation using the whole program optimization on gcc where it completely reordered all the global variables around as part of the optimization process. That said, there is no such guarantee for such kind of layouts for separate variables in C++.
This happen not just with structs. Individual variables usually are contiguous, but as everybody said, that's not guaranteed (indeed, in my box, the order is inverted for the following example)
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);
Result is
a value: 4 b value: 2
精彩评论