请解释名称错位,工作原理,解决的问题以及使用的上下文和语言。命名修改策略(例如编译器选择的名称和原因)加号。
答案 0 :(得分:36)
在您选择的编程语言中,如果标识符是从单独编译的单元导出的,则它需要一个在链接时已知的名称。名称mangling 解决了编程语言中标识符过载的问题。 (如果在多个上下文中使用相同的名称或具有多个含义,则标识符将“重载”。)
一些例子:
在C ++中,函数或方法get
可能会在多种类型下重载。
在Ada或Modula-3中,函数get
可能出现在多个模块中。
多种类型和多个模块涵盖了通常的背景。
典型策略:
将每种类型映射到字符串,并使用组合的高级标识符和“type string”作为链接时名称。在C ++中很常见(特别容易重载,因为只允许函数/方法和参数类型)和Ada(也可以重载结果类型)。
如果在多个模块或命名空间中使用标识符,请使用标识符的名称加入模块的名称,例如List_get
而不是List.get
。
根据链接时名称中哪些字符合法,您可能需要进行额外的修改;例如,可能需要使用下划线作为“转义”字符,因此您可以区分
List_my.get
- > List__my_get
这
List.my_get
- > List_my__get
(不可否认,这个例子已经到了,但作为编译器编写者,我必须保证源代码中的不同标识符映射到不同的链接时名称。这就是名称的全部原因和目的截断。)
答案 1 :(得分:24)
简单地说,名称修改是编译器更改源代码中标识符名称的过程,以帮助linker消除这些标识符之间的歧义。
答案 2 :(得分:4)
Name mangling是编译器修改对象的“已编译”名称的一种方法,使其与您以一致方式指定的名称不同。
这允许编程语言灵活地为多个编译对象提供相同的名称,并且具有查找适当对象的一致方法。例如,这允许具有相同名称的多个类存在于不同的名称空间中(通常通过将名称空间添加到类名中等)。
许多语言的运算符和方法重载更进一步 - 每个方法在编译库中都以“受损”名称结束,以允许一种类型的多个方法以相同的名称存在。
答案 3 :(得分:2)
在python中,名称修改是一个系统,通过该系统,类变量在类的内部和外部具有不同的名称。程序员通过在变量名的开头加上两个下划线来“激活”它。
例如,我可以用一些成员定义一个简单的类:
>>> class Foo(object):
... def __init__(self):
... self.x = 3
... self._y = 4
... self.__z = 5
...
在python实践中,以下划线开头的变量名是“internal”而不是类接口的一部分,因此程序员不应该依赖它。但是,它仍然可见:
>>> f = Foo()
>>> f.x
3
>>> f._y
4
以两个下划线开头的变量名仍然是公开的,但它是名称错误的,因此更难以访问:
>>> f.__z
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'Foo' object has no attribute '__z'
但是,如果我们知道名称修改是如何工作的,我们就可以了解它:
>>> f._Foo__z
5
即。 classname前置于带有额外下划线的变量名。
Python没有“私人”与“公共”成员的概念;一切都是公开的。名称修改是程序员可以发送的最强信号,不应该从类外部访问该变量。
答案 4 :(得分:2)
来源:http://sickprogrammersarea.blogspot.in/2014/03/technical-interview-questions-on-c_6.html
名称修改是C ++编译器使用的过程,为程序中的每个函数赋予唯一的名称。在C ++中,程序通常至少具有一些具有相同名称的函数。因此,名称修改可以被认为是C ++中的一个重要方面。
示例:强> 通常,成员名称是通过将成员的名称与类的名称连接而唯一生成的,例如鉴于声明:
class Class1
{
public:
int val;
...
};
val变成类似:
// a possible member name mangling
val__11Class1
答案 5 :(得分:0)
在Fortran中,需要进行名称修改,因为该语言不区分大小写,这意味着Foo,FOO,fOo,foo等将全部解析为相同的符号,其名称必须以某种方式进行规范化。不同的编译器以不同的方式实现修改,这在与C或使用不同编译器编译的二进制对象进行交互时会遇到很大的麻烦。例如,GNU g77 / g95总是在小写名称中添加一个尾随下划线,除非该名称已包含一个或多个下划线。在这种情况下,会添加两个下划线。
例如,以下例程
program test
end program
subroutine foo()
end subroutine
subroutine b_ar()
end subroutine
subroutine b_a_r()
end subroutine
生成以下错位符号:
0000000000400806 g F .text 0000000000000006 b_ar__
0000000000400800 g F .text 0000000000000006 foo_
000000000040080c g F .text 0000000000000006 b_a_r__
为了从C调用Fortran代码,必须调用正确损坏的例程名称(显然要考虑可能的不同修改策略才能真正独立于编译器)。要从fortran调用C代码,C编写的接口必须导出正确的损坏名称并将调用转发给C例程。然后可以从Fortran调用此接口。
答案 6 :(得分:0)
大多数面向对象语言都提供了函数重载功能。 功能重载 如果任何类具有多个具有相同名称但参数类型不同的函数&amp;数字,然后据说他们超载。函数重载允许您对不同的函数使用相同的名称。
超载功能的方法
如何通过名称修改实现功能重载?
C ++编译器在生成目标代码时区分不同的函数 - 它通过根据参数的类型和数量添加有关参数的信息来更改名称。这种添加附加信息以形成函数名称的技术称为名称管理。
C ++标准没有为名称修改指定任何特定技术,因此不同的编译器可能会将不同的信息附加到函数名称。
我在gcc4.8.4上运行了示例程序。
class ABC
{
public:
void fun(long a, long b) {}
void fun(float a, float b) {}
void fun(int a, float b) {}
};
int main()
{
ABC obj;
obj.fun(1l,2l);
obj.fun(1,2.3f);
obj.fun(3.2f,4.2f);
return 0;
}
这个程序有三个名为fun的函数,根据参数的数量及其类型有所不同。 这些函数名称被破坏如下:
ayadav@gateway1:~$ nm ./a.out |grep fun
000000000040058c W _ZN3ABC3funEff
00000000004005a0 W _ZN3ABC3funEif
000000000040057a W _ZN3ABC3funEll
答案 7 :(得分:0)
在设计链接编辑器时,C,FORTAN和COBOL等语言没有名称空间,类,类成员和其他类似的东西。名称修改需要支持面向对象的功能,例如那些带有不支持它们的链接编辑器的功能。链接编辑器不支持其他功能的事实经常被遗漏;人们通过说链接编辑器需要名称修改来暗示它。
由于语言要求之间的差异很大,以支持名称修改的功能,因此没有简单的解决方案来解决如何在链接编辑器中支持它的问题。链接编辑器旨在使用来自各种编译器的输出(对象模块),因此必须具有支持名称的通用方法。
答案 8 :(得分:0)
所有先前的答案都是正确的,但这是Python的观点/示例示例。
定义
当类中的变量的前缀为__(即两个下划线)且后缀为__(即两个下划线或更大的下划线)时,则该变量被视为私有标识符。 Python解释器会转换所有私有标识符,然后将名称转换为_class__identfier
Example:
MyClassName --> _myClassName
__variable --> __variable
为什么
之所以需要这样做,是因为避免了可能由覆盖属性引起的问题。换句话说,为了重写,Python解释器必须能够为子方法和父方法建立不同的id,并使用__(双下划线)使python能够做到这一点。在下面的示例中,如果没有__help,则此代码将无效。
class Parent:
def __init__(self):
self.__help("will take child to school")
def help(self, activities):
print("parent",activities)
__help = help # private copy of original help() method
class Child(Parent):
def help(self, activities, days): # notice this has 3 arguments and overrides the Parent.help()
self.activities = activities
self.days = days
print ("child will do",self.activities, self.days)
# the goal was to extend and override the Parent class to list the child activities too
print ("list parent & child responsibilities")
c = Child()
c.help("laundry","Saturdays")
答案 9 :(得分:0)
这里的答案很棒,所以这只是我的一点经验:我使用名称修改来知道什么工具(gcc / vs / ...)以及参数如何传递到堆栈中以及什么调用约定我正在处理,并且基于名称,因此例如,如果看到_main
,我知道对其他人来说是Cdecl