在 C++ 中命名 Mangling 和 extern “C”

简介: C++ 支持函数重载,即可以有多个同名但不同参数的函数。C++ 编译器在生成目标代码时如何区分不同的函数——它通过添加有关参数的信息来更改名称。这种向函数名称添加附加信息的技术称为Name Mangling。C++ 标准没有指定任何特定的名称修改技术,因此不同的编译器可能会向函数名称附加不同的信息。 

「这是我参与11月更文挑战的第20天,活动详情查看:2021最后一次更文挑战


C++ 支持函数重载,即可以有多个同名但不同参数的函数。C++ 编译器在生成目标代码时如何区分不同的函数——它通过添加有关参数的信息来更改名称。这种向函数名称添加附加信息的技术称为Name Mangling。C++ 标准没有指定任何特定的名称修改技术,因此不同的编译器可能会向函数名称附加不同的信息。


考虑以下 Name Mangling 示例,其中包含函数f() 的各种声明

int f(void) { return 1; }
int f(int) { return 0; }
void g(void) { int i = f(), j = f(0); }
复制代码


一些 C++ 编译器可能会将上述名称改写为以下名称,

int __f_v(void) { return 1; }
int __f_i(int) { return 0; }
void __g_v(void) { int i = __f_v(), j = __f_i(0); }
复制代码

注意:  C 不支持函数重载,因此,当我们在 C++ 中链接 C 代码时,我们必须确保符号的名称不被更改。

从 C++ 链接时如何处理 C 符号?


在 C 中,名称可能不会被修改,因为它不支持函数重载。那么当我们在 C++ 中链接 C 代码时,如何确保符号的名称不被更改。例如,请参阅以下使用 C 的 printf() 函数的 C++ 程序。

#include <stdio.h>
int printf(const char* format, ...);
int main()
{
  printf("haiyong");
  return 0;
}
复制代码


上述程序产生错误。


解释: 编译错误的原因很简单,c++编译器修改了printf() 的名字,没有找到新名字的函数定义。


解决方案:  C++ 中的 Extern “C”


当一些代码被放入 extern “C” 块时,C++ 编译器确保函数名是未修改的——编译器发出一个名称不变的二进制文件,就像 C 编译器会做的那样。


如果我们把上面的程序改成下面这样,程序就可以正常工作并在控制台上打印“haiyong”(如下所示)。

#include <bits/stdc++.h>
using namespace std;
extern "C" {
int printf(const char* format, ...);
}
int main()
{
  printf("haiyong");
  return 0;
}
复制代码


输出

haiyong
复制代码


因此,所有 C 风格的头文件(stdio.h、string.h 等)在 extern “C”块中都有它们的声明。

#ifdef __cplusplus
extern "C" {
#endif
// Declarations of this file
#ifdef __cplusplus
}
#endif
复制代码


以下是上面讨论的要点:


1. 由于 C++ 支持函数重载,因此必须在函数名称中添加附加信息(称为 Name mangling)以避免二进制代码中的冲突。


2.  C 中不能更改函数名称,因为它不支持函数重载。为了避免链接问题,C++ 支持 extern “C” 块。C++ 编译器确保 extern “C” 块内的名称不会更改。

如果您发现任何不正确的内容,或者您想分享有关上述主题的更多信息,请发表评论。



目录
相关文章
|
3月前
|
存储 编译器 C语言
详解C/C++中的static和extern
本文详解了C/C++中`static`和`extern`关键字的用法和区别,通过具体代码示例说明了在不同情境下如何正确使用这两个关键字,以及`extern "C"`在C++中用于兼容C语言库的特殊作用。
109 4
详解C/C++中的static和extern
|
5月前
|
NoSQL API Redis
c++开发redis module问题之为什么在使用RedisModule_GetApi之前要通过((void**)ctx)[0]这种方式获取其地址
c++开发redis module问题之为什么在使用RedisModule_GetApi之前要通过((void**)ctx)[0]这种方式获取其地址
|
7月前
|
存储 编译器 C语言
【C/C++ 关键字 存储类说明符 】一文带你了解C/C++ 中extern 外部声明 关键字的使用
【C/C++ 关键字 存储类说明符 】一文带你了解C/C++ 中extern 外部声明 关键字的使用
124 1
|
7月前
|
编译器 C++
面试题:C++ extern作用?
面试题:C++ extern作用?
77 0
|
存储 Cloud Native Linux
C++ extern关键字作用
C++ extern关键字作用
|
程序员 C++ Windows
Windows C++ 使用PIPE命名管道实现进程间通讯
本文章是介绍在Windows下,使用PIPE管道实现进程间通讯,可是实现两个进程之前相互发送读取消息。
251 0
|
编译器 C语言 C++
C++ 中 extern 数组和指针
C++ 中 extern 数组和指针
153 0
|
人工智能 编译器 Linux
【重学C/C++系列(二)】:extern关键字用法全解析
extern 是C/C++语言中**表明全局变量或者函数作用范围(可见性)的关键字**,编译器收到extern通知,则其声明的变量或者函数可以在本模块或者其他模块使用。
【重学C/C++系列(二)】:extern关键字用法全解析
|
编译器 Linux C语言
C++学习笔记(二)——extern “C“ 用法详解
C++学习笔记(二)——extern “C“ 用法详解
C++学习笔记(二)——extern “C“ 用法详解