C ++编译器 - 解析类成员的名称

时间:2009-11-06 00:06:36

标签: c++ compiler-construction

当编译器看到这段代码时:

SomeClass foo;
int x = foo.bar;

检索 bar 的值时,它的过程是什么?即它会看一些代表类定义的数据结构吗?如果是这样的数据结构是在编译时还是在运行时生成的?

5 个答案:

答案 0 :(得分:6)

编译器的地址为foo。在该地址,有足够的空间用于成员变量(sizeof(SomeClass)),其中可能包含一些填充。

它知道`bar在类中的某个位置(通常是它们被声明的顺序,加上一些其他魔法,如继承),然后跳转到该偏移量。

那是:

struct SomeClass
{
    short s;
    float f;
    int bar;
    char *c;
}

// pseudo-code:
&SomeClass.bar == (&SomeClass) + sizeof(short) + sizeof(float);

在运行时,它获取该数据,并将其分配给x

答案 1 :(得分:4)

在编译时,编译器将有一些数据结构,告诉它如何访问SomeClass的每个成员。对于简单的情况,它只是一个偏移量,但如果你有非平凡的继承,它可能会有更多。

为了处理表达式,编译器会查询此内部数据并(最终)发出相应的机器代码。通过运行时,这个结构将被抛弃,剩下的就是从foo的地址开始,为了做任何需要而发出的代码。但是,如果你有一个指向bar的成员指针,那么如何访问bar成员的细节以某种方式封装在该指针值中(可能是一个偏移量,可能更复杂)。

答案 2 :(得分:2)

当编译器看到SomeClass的定义时,该过程开始。根据该定义,它构建一个内部结构,其中包含SomeClass中字段的类型,以及SomeClass方法的代码位置。

当您编写SomeClass foo;时,编译器会找到与SomeClass构造函数对应的代码,并创建调用该代码的机器指令。在下一行,你写int x = foo.bar。这里编译器编写机器指令以为int分配堆栈空间,然后查看其SomeClass的数据结构。该数据结构将告诉它bar对象开头的foo的字节偏移量。然后编译器写入机器代码,将对应bar的字节复制到x的内存中。所有这些机器代码都会写入您的可执行文件。

通常,编译完成后,表示SomeClass和其他定义的数据结构将被丢弃。你剩下的只是一套机器指令。当您实际运行程序时执行这些指令,以便SomeClass的构造函数和将foo.bar复制到x的代码由CPU执行任何关于对象结构的明确知识。

这是一般情况。当您在调试器下运行代码并进行优化时,有一些特殊情况,但这通常是 会发生什么。

答案 3 :(得分:1)

你必须认为在编译期间每个类都变成了一个结构(为了简化说明),所以如果你有

class Foo
{
   int x, y, z;
   char bar[10];
   ... etc ...
}

它们被转换为具有指定大小的结构,在这种情况下为4 * 3 + 10个字节。然后它根据对齐方式以更方便的方式排列它们,记住例如在偏移4处你可以找到属性y,而在地址8你可以找到z。

然后这很简单,只需将4添加到分配所涉及的类的地址中,然后获取y的地址,依此类推。

答案 4 :(得分:1)

编译器仅在编译时存储此类类元数据。你的第一个问题是,它如何检索bar的值,实际上非常复杂。您可以将其视为计算bar与对象foo的偏移量,然后读取该位置的内存。然而,根据x的实际使用方式,它可以做一些不同的事情。在某些情况下,“x”可能根本不会出现在已编译的代码中。