我最近接到了一个C ++访谈,我被问到,编译器如何区分两个不同类中具有相同名称的静态数据成员?
由于所有静态数据变量都存储在数据段中,因此编译器必须通过这种方式跟踪哪些静态数据属于哪个类,尤其是当它们具有相同名称时。
编辑: 我回答了名字错误,但他拒绝说名字错误仅在同一类成员中使用。
答案 0 :(得分:12)
名称在其中包含了类名。 clang编译器的一个例子
class A {
static int i;
};
int A::i = 0;
输出
$ clang++ -cc1 -emit-llvm main1.cpp -o -
; ModuleID = 'main1.cpp'
target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:32:32-n8:16:32"
target triple = "i386-pc-linux-gnu"
@_ZN1A1iE = global i32 0, align 4
_ZN1A1iE
$ c++filt _ZN1A1iE
A::i
答案 1 :(得分:6)
它是实现定义的,因此没有任何一种方法可以完成。
Name mangling是常用的。
答案 2 :(得分:2)
好吧我会假设通过名称修改,类的名称也用数据编码。如果它像为名称前缀一样简单,我不会感到惊讶:
class one
{
static int data;
};
class two
{
static int data;
};
可以有名字
one::data
two::data
在数据段中。这些都是独特的名字。
答案 3 :(得分:2)
一个名字只是人类用来赋予事物意义的东西。
一旦编译器知道它们是不同的项(因为它们在不同的类中声明),它将不会使用该名称来区分它们在二进制文件中,它将使用指针和指针不关心名称:)
然后没有禁止在封闭类之前添加数据名称..
答案 4 :(得分:2)
所有“名称修改”的答案都解决了调试器如何找到每个符号的存储以及链接器如何知道差异,但编译器知道,因为这些实体占用符号表中的不同条目。
就是这样。
可执行文件不需要知道任何有关名称的内容{*}。只是位置。编译器知道名称,知识在符号表中编码(但可以实现)。
{*}嗯,无论如何都没有RTTI。
答案 5 :(得分:1)
该类的名称限定成员的名称:myclass::mymemb
。当从类外部引用它们时,编译器会以与您相同的方式对它们进行区分。
在实现中,这是由 name mangling 完成的;编译器对类的名称和成员的名称进行santizes处理,并将它们连接成一个混乱,例如__i_7myclass_6mymemb
。
名称修改过程(或其必要性)是我们需要extern "C"
与C接口兼容的原因,C接口定义了非破坏名称。
答案 6 :(得分:0)
static
成员的名称会被修改,以至于类名是链接器看到的“全局”名称的一部分。
答案 7 :(得分:0)
它将类名附加到数据成员名称。 (然后命名 - 破坏整个事情。)