2017-04-07 59 views
0

在下面的例子(试行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; 
} 

无论是结构和其结构nestd具有相同的存储器位置。这是有道理的,因为要存储在内存中的第一个元素是嵌套结构的一部分。

证明:0x7ffd895f86e0 0x7ffd895f86e0

我的问题是:如何编译器知道存储什么类型的在这个位置上,是有从跟踪在运行时这些信息的任何开销可以预料?

+1

它知道是因为你写了'struct a'的定义,这使得清楚并且被编译器理解。运行时不需要这些信息。 – nwp

+0

所以你说的a1和测试的位置是一样的 - 但是这与结构a的第一个成员的位置相同,与结构的位置相同。当这样放置时,它仍然是意想不到的? – UKMonkey

+0

编译器实现具有关于如何组织嵌套结构的硬编码知识。 – Peter

回答

2

如何:

struct a { 
    int x; 
    struct b { 
     int b1; 
    }; 
    b a1; 
    int a2; 
}; 

他们有相同的地址?不。不是因为它们不同,而是因为“struct”没有二进制含义(在抨击之前,请继续阅读)。当你的程序被编译时,所有重要的是你的结构中的变量。编程语言有这种表面的东西叫做“结构”,让你的工作变得简单。但这不是真实的,除非你做了一些需要将它作为一件事情来处理的事情(比如复制它),即使如此,生成的二进制代码(用于运行时)也只会代表要复制的元素一个整体,而不是“结构”本身。

当你实例a那里,这是怎么看起来像在内存:

int x - int b1 - int a2 

它的块内存整数。这不是结构。

您可以使用指针进行验证。在你的代码中:

*(int*)(&test) //is b1 
*((int*)(&test)+1) //is a2 

所以你看在内存中只有两个整数是重要的。 PS:请注意,所有这一切都假设我们没有处理多态,它增加了更多的表示vtable的内存块。这是另一天的故事。

+0

这个描述适用于没有优化开启的明智平台上的标准布局类,但通过虚拟函数和虚拟继承快速分解。 – Quentin

+0

@Quentin用虚拟的东西,这绝对会中断,这就是为什么二进制接口是用C而不是C++完成的原因。但我认为这很深。我要添加更多关于这方面的信息。 –

0

让“画”的结构看起来如何在内存中(连同“指针”的话):

 
+----+----+ 
| a1 | a2 | 
+----+----+ 
^ ^
| | 
| &test.a2 
| 
&test 
| 
&test.a1 

这应该希望相当明确如何两种不同的结构可以占用相同的内存。

应该指出,这只适用于具有非虚函数的结构。虚函数可能会导致其他隐藏成员被包含在对象中。

0

实际上,您是通过编写表达式(例如& test和&(test.a1))来明确告诉编译器何种类型存储在给定位置的。

1

忘记你正在处理结构的那一刻。编译器如何知道某个特定的内存位置是否包含intfloat?从某种意义上说,事实并非如此。但在程序中,变量有一个类型类型告诉编译器什么操作对该变量有效。不管该对象的地址是什么;重要的是该计划所说的是什么类型。所以:

int i = 3; 
i = i + 1; 

编译器知道怎么做,此外,由于节目中说对待命名iint值的存储位置。

float f = 4.0; 
f = f + 1; 

编译器知道怎么做,此外,由于节目中说对待命名f作为float值的存储位置。

在你的例子中,test.a1.b1的类型为int,因为程序这么说。而且test.a1有类型a :: b because the program said so. And测试has type a`因为程序这么说。

相关问题