什么是名字改编,以及它是如何工作的?(What is name mangling, and how

2019-06-18 17:08发布

请解释一下什么是名字改编,它是如何工作的,它解决了什么问题,并在其中的背景和语言被使用。 名称重整战略的一个加号(如什么名字是由编译器,以及为什么选择)。

Answer 1:

在您选择的编程语言,如果一个标识符是从单独编译单元出口,它需要通过其所在链接时已知的名称。 名称重整解决了编程语言超载标识符的问题 。 (标识符为“过载”,如果相同的名称是在多于一个的上下文或与多于一个的含义。)

一些例子:

  • 在C ++中,函数或方法get可以在多种类型的过载。

  • 在阿达或MODULA-3,函数get可能出现在多个模块。

多种类型和多种模块涵盖了常用的上下文。

典型策略:

  • 每种类型映射到串并使用组合的高级标识符和“类型字符串”作为链接时命名。 常见于C ++(因为超载特别容易只允许用于功能/方法,并且只在参数类型)和Ada(可过载的结果类型以及)。

  • 如果一个标识符在多于一个模块或命名空间中使用,加入了模块的名称与标识符的名称,例如, List_get代替List.get

根据哪些字符是在链接时的名字法律,你可能需要做更多的忙玲; 例如,它可能有必要使用下划线作为“逃离”字符,所以可以区分

  • List_my.get - > List__my_get

  • List.my_get - > List_my__get

(诚然,这例子是达到了,但作为一个编译器作者,我必须保证源代码的地图,不同的链接时的名字不同的标识符 。这就是全部的原因和目的的名字改编。)



Answer 2:

简单地说,名称重整是由编译器改变标识符在源代码中的名称,以帮助一个过程链接在这些标识符之间的多义性。

维基百科对这一主题的精彩的文章有几个很好的例子。



Answer 3:

名称重整是由编译器修改对象的“编译”的名字,使它比你以一致的方式指定什么不同的手段。

这允许编程语言的灵活性,提供相同的名字多次,编译对象,并有一个一致的方法来查找适当的对象。 例如,这允许多个类具有相同名称的不同的命名空间存在(通常通过预先命名空间进入类名等)。

运营商和方法重载在许多语言中,这进一步退一步 - 每种方法,以允许在一个类型的多个方法具有相同的名称存在结束了一个“错位”的名字在编译库。



Answer 4:

在蟒蛇,名称重整是由类变量有内部和外部类不同名的系统。 程序员通过把两个下划线在变量名的开头“激活”它。

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

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

在蟒蛇的做法,开始用下划线变量名是“内部”,而不是类接口的一部分,因此程序员不应该依赖于它。 然而,它仍然是可见的:

>>> 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

即类名的前面加上变量名与一个额外的下划线。

Python有没有“私人”与“公众”成员的概念; 一切都是公开的。 名称 - 重整是一个程序员可以发送变量不应从类外部访问最强的,可能的信号。



Answer 5:

来源: 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


Answer 6:

在Fortran中,需要名字改编因为语言是不区分大小写的,这意味着富,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代码,在适当错位的例程名必须调用(显然保持到可能不同的mangling策略要真正编译器无关)。 要调用从FORTRAN C代码,一个C编写的接口必须正确出口错位的名称,并调用转发给C例程。 该接口然后可以从Fortran调用的。



Answer 7:

大多数面向对象语言提供了函数重载功能。 函数重载如果任何类具有相同的名称,但不同的参数类型及号码,然后他们说,超载多种功能。 函数重载允许您使用相同的名称为不同的功能。

方法重载函数

  1. 通过改变参数的数量。
  2. 列表项由具有不同类型的说法。

如何函数重载与名字改编实现?
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;
}

这个程序有3个功能命名的乐趣不同,基于的参数和它们的类型号。 这些函数的名字是被损毁,如下图所示:

ayadav@gateway1:~$ nm ./a.out |grep fun
000000000040058c W _ZN3ABC3funEff
00000000004005a0 W _ZN3ABC3funEif
000000000040057a W _ZN3ABC3funEll
  • ABC是类名的命令字符串
  • 有趣的是函数名普通字符串
  • FF 2浮子> F型的参数
  • LL 2长> 1的typeof参数
  • 如果第一个整数argument-> i和一个浮子>˚F参数


Answer 8:

在链接编辑设计时,语言,如C,FORTAN和COBOL没有的类和其他事情的命名空间,类成员。 名称重整需要支持面向对象的特性,例如那些不支持他们的链接编辑器。 该链接编辑器不支持的附加功能常常被漏诊的事实; 人们通过说名字改编由于链接编辑器需要的暗示吧。

由于有语言要求中这么多的变化,支持名字改编做什么,没有一个简单的解决方案如何支持它的链接编辑器的问题。 链接编辑器的设计与各种编译器的输出(对象模块)的工作,因此必须有一个普遍的方式来支持的名字。



Answer 9:

所有以前的答案是正确的,但这里是例如Python的观点看/推理。

定义

在类中的变量有__(即两个下划线)的前缀没有__(即两个下划线或更多)的后缀,然后它被认为是私人identfier。 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")


Answer 10:

这里的答案是真棒,所以这是刚刚从我的一点经验加成:我为了知道使用名字改编,用什么工具(GCC / VS / ...),以及如何传递到栈参数,什么调用约定我是处理,并基于该名称,因此,例如,如果看到_main我知道这是一个Cdecl他人相同



文章来源: What is name mangling, and how does it work?