当编译器看到这段代码时:
SomeClass foo;
int x = foo.bar;
在检索bar的值时,它是通过什么过程进行的?即,它是否查看表示类定义的某些数据结构?如果是这样,那么这个数据结构是在编译时还是运行时生成的?
SomeClass foo;
int x = foo.bar;
在检索bar的值时,它是通过什么过程进行的?即,它是否查看表示类定义的某些数据结构?如果是这样,那么这个数据结构是在编译时还是运行时生成的?
foo
的地址,该地址有足够的空间存储成员变量(sizeof(SomeClass)
),其中可能包括一些填充。struct SomeClass
{
short s;
float f;
int bar;
char *c;
}
// pseudo-code:
&SomeClass.bar == (&SomeClass) + sizeof(short) + sizeof(float);
运行时,它获取数据并将其分配给x
SomeClass
的定义。基于该定义,它构建了一个内部结构,其中包含 SomeClass
中字段的类型以及方法代码的位置。SomeClass foo;
时,编译器会找到对应于 SomeClass
的 构造函数 的代码,并创建调用该代码的机器指令。在下一行中,你写下 int x = foo.bar
。这里编译器会写出机器指令来为 int
分配堆栈空间,然后查看其 SomeClass
数据结构。该数据结构将告诉它从 foo
对象开始的 bar
的字节偏移量。编译器然后会写出机器码将与 bar
相应的字节复制到 x
的内存中。所有这些机器码都被写入你的可执行文件中。SomeClass
和其他定义的数据结构都会被丢弃。剩下的只是一组机器指令。当你实际运行程序时,这些指令会被执行,因此构造函数和将 foo.bar
复制到 x
的代码会由 CPU 执行,而不需要显式了解对象的结构。class Foo
{
int x, y, z;
char bar[10];
... etc ...
}
它们被转换成一个具有指定大小的结构体,这里是4*3 + 10字节。然后,根据对齐方式将它们更方便地排列,记住例如在偏移量4处可以找到属性y,在地址8处可以找到z。
然后很容易,只需将参与赋值的类的地址加上4,就可以得到y等的地址。
sizeof(int)
来代替数字4。因为int
类型的字节数并不一定是4个字节。 - GManNickG