关于C ++中名称修改的问题

时间:2010-05-30 02:02:07

标签: c++ c compilation linker name-mangling

我正在尝试学习和理解C ++中的名称修改。以下是一些问题:

(1)来自devx

  

当全局函数重载时,为每个重载版本生成的受损名称都是唯一的。名称修改也适用于变量。因此,局部变量和具有相同用户给定名称的全局变量仍会获得明显的错位名称。

除了重载函数和同名全局变量和局部变量之外,还有其他使用名称修改的示例吗?

(2)来自Wiki

  

需要使用语言允许使用相同的标识符命名不同的实体,只要它们占用不同的命名空间(其中命名空间通常由模块,类或显式命名空间指令定义)。

我不太明白为什么名称修改仅适用于标识符属于不同名称空间的情况,因为重载函数可以在同一名称空间中,同名全局变量和局部变量也可以在同一空间中。怎么理解这个?

具有相同名称但在不同范围内的变量是否也使用名称修改?

(3)C是否有名称错误?如果没有,当一些全局和局部变量具有相同名称时,它如何处理? C没有重载功能,对吧?

谢谢和问候!

6 个答案:

答案 0 :(得分:26)

C没有进行名称修改,但它确实在函数名前加了一个下划线,因此printf(3)实际上是{c}对象中的_printf

在C ++中,故事有所不同。它的历史是最初的Stroustrup创建了“C with classes”或cfront,这是一个将早期C ++转换为C的编译器。然后其他工具--C编译器和链接器将用于生成目标代码。这暗示C ++名称必须以某种方式转换为C名称。这正是name mangling的作用。它为每个类成员和全局/命名空间函数和变量提供唯一的名称,因此命名空间和类名(用于解析)和参数类型(用于重载)以某种方式包含在最终的链接器名称中。

使用像nm(1)这样的工具很容易看到 - 编译C ++源代码并查看生成的符号。以下是关于GCC的OSX:

namespace zoom
{
    void boom( const std::string& s )
    {
        throw std::runtime_error( s );
    }
}

~$ nm a.out | grep boom
0000000100001873 T __ZN4zoom4boomERKSs

在C和C ++中,本地(自动)变量不产生符号,而是存在于寄存器或堆栈中。

编辑:

局部变量在结果对象文件中没有名称,仅仅是因为链接器不需要知道它们。所以没有名字,没有错误。其他一切(链接器必须查看)在C ++中被命名为。

答案 1 :(得分:16)

Mangling就是编译器如何让链接器满意。

在C中,无论如何都不能有两个具有相同名称的函数。这就是链接器编写的假设:唯一名称。 (您可以在不同的编译单元中使用静态函数,因为链接器不关心它们的名称。)

在C ++中,只要具有不同的参数类型,就可以拥有两个具有相同名称的函数。所以C ++ 以某种方式将函数名称与类型结合起来。这样链接器将它们视为具有不同的名称。

请注意,名称如何被破坏并不重要,实际上每个编译器都会以不同方式执行。重要的是,具有相同基本名称的每个函数都以某种方式对于链接器而言是唯一的。

您现在可以看到,在混合中添加名称空间和模板不断扩展原则。

答案 2 :(得分:9)

从技术上讲,它是“装饰”。这听起来不那么粗糙,但也有一种暗示,CreditInterest可能会被重新排列到IntCrederestit,而实际发生的更像是_CreditInterest@4,这可以说是“装饰”而不是错位。也就是说,我称它为mangling :-)但是如果你搜索“C ++名称装饰”,你会发现更多的技术信息和例子。

答案 3 :(得分:5)

除了重载函数和同名全局变量和局部变量之外,还有其他使用名称修改的示例吗?

C ++总是所有符号。它对编译器来说更容易。通常情况下,修改会对参数列表或类型进行编码,因为这些是导致需要修改的最常见原因。

C不会破坏。范围确定用于控制对同名的本地和全局变量的访问。

答案 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)

agner提供了有关什么是名称修饰以及如何在不同的编译器中进行操作的更多信息。

  

名称修饰(也称为名称修饰)是C ++使用的方法   编译器将附加信息添加到函数名称和   对象文件中的对象。链接器在以下情况下使用此信息:   一个模块中定义的功能或对象是从另一个模块引用的   模块。名称修饰具有以下目的:

     
      
  1. 链接程序可以区分不同版本的重载函数。
  2.   
  3. 链接器可以检查是否在所有模块中以完全相同的方式声明了对象和函数。
  4.   
  5. 链接程序可以在错误消息中提供有关未解析引用类型的完整信息。
  6.   
     

发明名称修饰是为了实现目的1。其他目的   是所有编译器未完全支持的次要好处。的   名称必须提供的最少信息是名称   函数及其所有参数的类型以及任何   类或名称空间限定符。可能的其他信息   包括返回类型,调用约定等。   信息被编码为一个ASCII文本字符串,看起来像   对人类观察者来说是神秘的。链接器不必知道什么   该代码意味着为了实现目的1和2。它只需要   检查字符串是否相同。