如果嵌套对象具有相同的地址,编译器如何区分?

时间:2017-04-07 11:13:14

标签: c++ object-model

在以下示例中(尝试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

我的问题是:编译器如何知道在这个位置存储了哪些类型,并且在运行时跟踪此类信息是否有任何开销?

4 个答案:

答案 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)

暂时忘记你正在处理结构。编译器如何知道特定的内存位置包含intfloat?从某种意义上说,它没有。但在程序中,变量具有类型类型告诉编译器哪些操作对该变量有效。对象的地址是什么并不重要;重要的是程序所说的类型。所以:

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)等表达式,明确告诉编译器在给定位置存储了什么类型。