如果嵌套对象具有相同的地址,编译器如何区分它们?
How does the compiler distinguish nested objects if they have the same address?
在下面的例子中(试试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;
}
该结构及其嵌套结构都具有相同的内存位置。这是有道理的,因为存储在内存中的第一个元素是嵌套结构的一部分。
证明:0x7ffd895f86e0 0x7ffd895f86e0
我的问题是:编译器如何知道此位置存储的类型以及在运行时跟踪此类信息是否会产生预期的开销?
这个怎么样:
struct a {
int x;
struct b {
int b1;
};
b a1;
int a2;
};
他们有相同的地址吗?不,不是因为它们不同,而是因为 "struct" 没有二进制含义(在抨击这个之前,请继续阅读)。编译程序时,重要的是结构中的变量。编程语言有一个叫做 "struct" 的肤浅的东西,可以让事情变得简单。但它不是真实的,除非你做一些需要它作为一个事物处理的东西(比如复制它),即使那样生成的二进制代码(对于 运行-time)也只会代表那些元素要作为一个整体复制,而不是 "struct" 本身。
当你在那里实例化 a
时,它在内存中是这样的:
int x - int b1 - int a2
它是内存中的整数块。这不是结构。
您可以使用指针来验证这一点。在您的代码中:
*(int*)(&test) //is b1
*((int*)(&test)+1) //is a2
所以你看到内存中只有两个整数是重要的。
PS:请注意,所有这些都假设我们没有处理多态性,多态性会添加更多表示 vtable 的内存块。这是另一天的故事。
让 "draw" 结构在内存中的样子(连同 "pointers" 到它):
+----+----+
| a1 | a2 |
+----+----+
^ ^
| |
| &test.a2
|
&test
|
&test.a1
这应该可以很清楚地说明两个不同的结构如何占用相同的内存。
需要注意的是,这仅适用于具有非虚函数的结构。虚函数可能导致对象中包含其他隐藏成员。
实际上是你通过写 &test 和 &(test.a1) 等表达式明确地告诉编译器在给定位置存储的是什么类型。
暂时忘记您正在处理结构。编译器如何知道特定内存位置包含 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::bbecause the program said so. And
testhas type
a` 因为程序是这么说的。
在下面的例子中(试试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;
}
该结构及其嵌套结构都具有相同的内存位置。这是有道理的,因为存储在内存中的第一个元素是嵌套结构的一部分。
证明:0x7ffd895f86e0 0x7ffd895f86e0
我的问题是:编译器如何知道此位置存储的类型以及在运行时跟踪此类信息是否会产生预期的开销?
这个怎么样:
struct a {
int x;
struct b {
int b1;
};
b a1;
int a2;
};
他们有相同的地址吗?不,不是因为它们不同,而是因为 "struct" 没有二进制含义(在抨击这个之前,请继续阅读)。编译程序时,重要的是结构中的变量。编程语言有一个叫做 "struct" 的肤浅的东西,可以让事情变得简单。但它不是真实的,除非你做一些需要它作为一个事物处理的东西(比如复制它),即使那样生成的二进制代码(对于 运行-time)也只会代表那些元素要作为一个整体复制,而不是 "struct" 本身。
当你在那里实例化 a
时,它在内存中是这样的:
int x - int b1 - int a2
它是内存中的整数块。这不是结构。
您可以使用指针来验证这一点。在您的代码中:
*(int*)(&test) //is b1
*((int*)(&test)+1) //is a2
所以你看到内存中只有两个整数是重要的。
PS:请注意,所有这些都假设我们没有处理多态性,多态性会添加更多表示 vtable 的内存块。这是另一天的故事。
让 "draw" 结构在内存中的样子(连同 "pointers" 到它):
+----+----+ | a1 | a2 | +----+----+ ^ ^ | | | &test.a2 | &test | &test.a1
这应该可以很清楚地说明两个不同的结构如何占用相同的内存。
需要注意的是,这仅适用于具有非虚函数的结构。虚函数可能导致对象中包含其他隐藏成员。
实际上是你通过写 &test 和 &(test.a1) 等表达式明确地告诉编译器在给定位置存储的是什么类型。
暂时忘记您正在处理结构。编译器如何知道特定内存位置包含 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::bbecause the program said so. And
testhas type
a` 因为程序是这么说的。