Reputation: 5467
In the following example (try out here)
#include <iostream>
using namespace std;
struct a {
struct b {
int b1;
};
b a1;
int a2;
};
int main() {
a test;
test.a1.b1 = 5;
test.a2 = 6;
std::cout<<&test<<" "<<&(test.a1);
// your code goes here
return 0;
}
Both the struct and its nestd struct have the same memory location. This makes sense, since the first element to be stored in memory is part of the nested struct.
Proof: 0x7ffd895f86e0 0x7ffd895f86e0
My question is: how does the compiler know what types are stored at this location and is there any overhead from tracking such information at runtime to be expected?
Upvotes: 0
Views: 170
Reputation: 26286
How about this:
struct a {
int x;
struct b {
int b1;
};
b a1;
int a2;
};
Do they have the same address? No. Not because they're different, but because "struct" has no binary meaning (before lashing this, keep reading). When your program is compiled, all that matters is the variables inside your structs. The programming language has this superficial thing called "struct" to make things easy for you. But it's not real, unless you do something that requires it to be handled as a one thing (such as copying it), and even then the binary code generated (for run-time) will only represent the elements that are to be copied as a whole, not the "struct", per se.
When you instantiate a
there, this is how it looks like in memory:
int x - int b1 - int a2
It's blocks in memory with ints. It's not structs.
You can verify this using pointers. In your code:
*(int*)(&test) //is b1
*((int*)(&test)+1) //is a2
So you see there's only two ints in memory that matter.
PS: Notice that all this assumes that we're not dealing with polymorphism, which adds more memory blocks that represent the vtable. That's a story for another day.
Upvotes: 2
Reputation: 76315
Forget for a moment that you're dealing with structs. How does the compiler know that a particular memory location holds an int
or a float
? In one sense, it doesn't. But within a program, variables have a type and that type tells the compiler what operations are valid on that variable. It doesn't matter what the address of the object is; what matters is what type the program says it is. So:
int i = 3;
i = i + 1;
The compiler knows how to do that addition because the program said to treat the memory location named i
as an int
value.
float f = 4.0;
f = f + 1;
The compiler knows how to do that addition because the program said to treat the memory location named f
as a float
value.
In your example, test.a1.b1
has type int
because the program said so. And test.a1
has type a::bbecause the program said so. And
testhas type
a` because the program said so.
Upvotes: 1
Reputation: 454
Actually it is you who explicitly tells the compiler what type is stored at a given location by writing expressions such as &test and &(test.a1).
Upvotes: 0
Reputation: 409196
Lets "draw" how the structure looks in memory (together with the "pointers" to it):
+----+----+ | a1 | a2 | +----+----+ ^ ^ | | | &test.a2 | &test | &test.a1
That should hopefully make it quite clear how two different structures can occupy the same memory.
It should be noted that this is only for structures with non-virtual functions. Virtual functions may cause other hidden members to be included in the objects.
Upvotes: 0