在以下示例中(尝试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;
}
struct及其nestd结构都具有相同的内存位置。这是有道理的,因为要存储在内存中的第一个元素是嵌套结构的一部分。
证明:0x7ffd895f86e0 0x7ffd895f86e0
我的问题是:编译器如何知道在这个位置存储了哪些类型,并且在运行时跟踪此类信息是否有任何开销?
答案 0 :(得分:2)
这个怎么样:
struct a {
int x;
struct b {
int b1;
};
b a1;
int a2;
};
他们有相同的地址吗?不。不是因为它们不同,而是因为“struct”没有二元意义(在绑定之前,请继续阅读)。编译程序时,重要的是结构中的变量。编程语言有一个称为“struct”的表面的东西,让你的事情变得简单。但这不是真的,除非你做一些事情要求它作为一件事(例如复制它)处理,即使这样生成的二进制代码(对于运行时)也只代表要复制的元素一个整体,而不是“结构”本身。
当你在那里实例化a
时,这就是它在内存中的样子:
int x - int b1 - int a2
它是内存中的块。它不是结构。
您可以使用指针验证这一点。在您的代码中:
*(int*)(&test) //is b1
*((int*)(&test)+1) //is a2
所以你看到内存中只有两个整数很重要。
PS:请注意,所有这些都假设我们没有处理多态性,这会增加更多代表vtable的内存块。这是另一天的故事。答案 1 :(得分:1)
暂时忘记你正在处理结构。编译器如何知道特定的内存位置包含int
或float
?从某种意义上说,它没有。但在程序中,变量具有类型,类型告诉编译器哪些操作对该变量有效。对象的地址是什么并不重要;重要的是程序所说的类型。所以:
int i = 3;
i = i + 1;
编译器知道如何进行添加,因为程序会将名为i
的内存位置视为int
值。
float f = 4.0;
f = f + 1;
编译器知道如何进行添加,因为程序会将名为f
的内存位置视为float
值。
在您的示例中,test.a1.b1
的类型为int
,因为程序是这样说的。 test.a1
类型为a :: b because the program said so. And
test has type
a`,因为程序是这样说的。
答案 2 :(得分:0)
让我们“画出”结构在内存中的外观(以及它的“指针”):
+----+----+ | a1 | a2 | +----+----+ ^ ^ | | | &test.a2 | &test | &test.a1
这应该很清楚,两个不同的结构如何占据相同的记忆。
应该注意,这仅适用于具有非虚函数的结构。虚函数可能会导致其他隐藏成员包含在对象中。
答案 3 :(得分:0)
实际上,通过编写&amp; test和&amp;(test.a1)等表达式,明确告诉编译器在给定位置存储了什么类型。