什么是名字?它是如何工作的?

请解释什么是名称混乱,它是如何工作的,它解决了什么问题,以及在哪些上下文和语言中使用。 命名破坏策略(例如,编译器select什么名字以及为什么)加号。

在您select的编程语言中,如果标识符是从单独编译的单元导出的,则需要在链接时知道它的名称。 名称修改解决了编程语言中重载标识符的问题 。 (如果在多个上下文中使用相同的名称或具有多个含义,则标识符是“重载”的。)

一些例子:

  • 在C ++中,函数或方法get可能会以多种types重载。

  • 在Ada或Modula-3中,函数get可能出现在多个模块中。

多种types和多个模块涵盖了通常的上下文。

典型的策略:

  • 将每个types映射到一个string,并使用组合的高级标识符和“typesstring”作为链接时间名称。 在C ++中是常见的(特别容易,因为重载只允许函数/方法,只允许参数types)和Ada(你也可以重载结果types)。

  • 如果标识符在多个模块或名称空间中使用,请使用标识符的名称(例如, List_get而不是List_get来连接模块的名称。

根据链接时间名称中的哪些字符是合法的,您可能需要进行额外的修改; 例如,可能需要使用下划线作为“逃逸”字符,以便您可以区分

  • List_my.get – > List__my_get

  • List.my_get – > List_my__get

(不可否认,这个例子已经到了,但是作为一个编译器编写者,我必须保证源代码中的不同标识符映射到不同的链接时间名称 ,这就是名称整理的全部原因和目的。

简而言之,name-mangling是编译器为了帮助链接器在这些标识符之间进行区分而改变源代码中标识符的名称的过程。

维基百科有一个关于这个问题的精彩文章,有几个很好的例子。

命名修改是编译器修改对象的“编译”名称的方法,使其与您以一致的方式指定的名称不同。

这允许编程语言灵活地为多个编译对象提供相同的名称,并且具有一致的方式来查找适当的对象。 例如,这允许具有相同名称的多个类存在于不同的名称空间中(通常通过将名称空间添加到类名称等中)。

在许多语言中,操作符和方法重载使得这一步更进一步 – 每个方法在编译的库中都以“mangled”名称结束,以便允许一种types的多个方法以相同的名称存在。

资料来源: http : //sickprogrammersarea.blogspot.in/2014/03/technical-interview-questions-on-c_6.html

Name mangling是C ++编译器使用的过程,为程序中的每个函数提供一个唯一的名称。 在C ++中,通常程序至less有一些具有相同名称的函数。 因此,在C ++中,名称可以被认为是一个重要的方面。

例子:通常情况下,成员名称是通过连接成员的名字和类的名字来唯一地生成的,比如声明如下:

 class Class1 { public: int val; ... }; 

val变成类似于:

  // a possible member name mangling val__11Class1 

在python中,name-mangling是类variables在类内部和外部具有不同名称的系统。 程序员通过在variables名称的开头加两个下划线来“激活”它。

例如,我可以用一些成员来定义一个简单的类:

 >>> class Foo(object): ... def __init__(self): ... self.x = 3 ... self._y = 4 ... self.__z = 5 ... 

在python练习中,以下划线开头的variables名是“internal”,而不是类接口的一部分,所以程序员不应该依赖它。 但是,它仍然是可见的:

 >>> f = Foo() >>> fx 3 >>> f._y 4 

以两个下划线开始的variables名仍然是公共的,但是名称是错位的,因此难以访问:

 >>> f.__z Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: 'Foo' object has no attribute '__z' 

如果我们知道这个名字是如何工作的,我们可以得到它:

 >>> f._Foo__z 5 

也就是说,类名前加了一个额外的下划线。

Python没有“私有”和“公共”成员的概念, 一切都是公开的。 名称修改是程序员可以发送的最强烈的信号,不应该从外部访问该variables。

在Fortran中,由于语言不区分大小写,所以需要命名修改,这意味着Foo,FOO,foo,foo等将全部parsing为相同的符号,其名称必须以某种方式进行归一化。 不同的编译器以不同的方式实现转换,当与用不同的编译器编译的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中调用。

大多数面向对象语言都提供了函数重载function。 函数重载如果任何一个类具有多个名称相同但参数types和编号不同的函数,则称它们被重载。 函数重载允许您为不同的函数使用相同的名称。

方法来重载一个函数

  1. 通过改变参数的数量。
  2. 列表项通过具有不同types的参数。

如何使用名称修饰实现函数重载?
C ++编译器在生成目标代码时会区分不同的函数 – 它会根据参数的types和数量添加有关参数的信息来更改名称。 这种添加附加信息来形成函数名称的方法称为Name Mangling。 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; } 

这个程序根据参数的数量和types有3个名为fun的函数。 这些函数的名字被破坏如下:

 ayadav@gateway1:~$ nm ./a.out |grep fun 000000000040058c W _ZN3ABC3funEff 00000000004005a0 W _ZN3ABC3funEif 000000000040057a W _ZN3ABC3funEll 
  • ABC是类名的命令string
  • 有趣的是函数名称的常用string
  • ff两个float-> ftypes的参数
  • 两个long-> ltypes的参数
  • 如果第一个整数参数 – >我和一个float-> f参数
Interesting Posts