请解释什么是名称修改、它是如何工作的、它解决什么问题以及使用的上下文和语言。名称修改策略(例如编译器选择什么名称以及为什么)一个加号。

有帮助吗?

解决方案

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

一些例子:

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

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

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

典型策略:

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

  • 如果一个标识符在多个模块或命名空间中使用,请将模块的名称与标识符的名称连接起来,例如, List_get 代替 List.get.

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

  • List_my.get -> List__my_get

  • List.my_get -> List_my__get

(诚​​然,这个例子已经达到了,但是作为编译器编写者,我必须保证 源代码中的不同标识符映射到不同的链接时名称. 。这就是名称修改的全部原因和目的。)

其他提示

简而言之,名称修改是编译器更改源代码中标识符名称的过程,以帮助 连接器 消除这些标识符之间的歧义。

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

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

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

操作和方法在许多语言超载这进一步采取步骤 - 每一种方法以允许在一种类型的多种方法具有相同名称的存在结束了一个“错位”的名字在编译库

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

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

>>> 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有没有“私人”与“公共”成员的概念;一切都是公开的。名称 - 重整是一个程序员可以发送可变不应从类的外部进行访问的最强-可能的信号。

来源: HTTP://sickprogrammersarea.blogspot。在/ 2014/03 /技术面试疑问的上c_6.html

名称重整是通过C ++编译器所用的方法让在你的程序的唯一名称每个功能。在C ++中,一般程序具有相同名称在-至少有几个功能。因此名称重整可被认为是在C ++的一个重要方面。

示例:             通常,会员名称唯一地通过与类例如的串接件的名称生成给出的声明:

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

VAL变得类似:

  // a possible member name mangling
     val__11Class1

在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的调用。

大多数面向对象语言都提供函数重载功能。函数重载如果任何类具有多个名称相同但参数类型和数量不同的函数,则称它们重载。函数重载允许您对不同的函数使用相同的名称。

重载函数的方法

  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 个名为 fun 的函数,它们根据参数数量及其类型而有所不同。这些函数名称的修改如下:

ayadav@gateway1:~$ nm ./a.out |grep fun
000000000040058c W _ZN3ABC3funEff
00000000004005a0 W _ZN3ABC3funEif
000000000040057a W _ZN3ABC3funEll
  • ABC 是类名的命令字符串
  • fun 是函数名称的公共字符串
  • ff 两个 float->f 类型的参数
  • ll 两个 long->l typeof 参数
  • 如果第一个整数参数 ->i 和一个浮点 ->f 参数

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

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

所有以前的答案是正确的,但这里是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")

这里的答案是真棒,所以这是刚刚从我的一点经验加成:我使用的名称才能知道,通过什么工具(GCC / VS / ...),以及如何参数到堆栈中,哪些调用约定重整我处理,并基于该名称,因此,例如,如果看到_main我知道这是一个Cdecl他人相同

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top