游戏艺术活动中心 - 最新网游活动与资讯

C/C++ 函数签名与名字修饰(符号修饰)

20世纪70年代以前,一个函数经过编译器编译后,存储在目标文件内的符号与函数名相同。比如定义一个函数func1,在目标函数中的符号名称也为func1。

但是随着汇编编写库的丰富,定义的函数很有可能与库中的函数名冲突。为了解决这一问题,编译器在将源代码编译成目标文件时,会将函数和变量的名字进行修饰,形成符号名,也就是符号修饰/名字修饰(Decorated Name)。

1、函数签名(Function Sginature)

函数签名包含了一个函数的信息,包括函数名、参数类型、所在类、名称空间及其他信息。

比如:

函数int func(int x)的函数签名为:int func(int)

每个函数签名对应一个修饰后的名字。

2、C语言中的名字修饰

Windows平台,C语言源代码文件中所有全局变量和函数经过编译后,符号名前加下划线“_”。

LINUX平台的gcc编译器中,默认去掉了C语言符号加下划线的方式。

fortran语言则前后都加下划线“_”。

比如

func1

Windows:_func1

LINUX:func1

fortran:_func1_

简单举个例子,aa.c文件中代码如下:

int f(int x)

{

return 0;

}

int main(int argc, char *argv[])

{

int j = f(1);

return 0;

}

Windows平台上,命令行输入:

cl aa.c

dumpbin /SYMBOLS aa.obj

生成可执行文件,然后利用dumpbin.exe工具查看符号名:

Linux平台上,输入

gcc aa.c

nm -a a.out

3、C++名字修饰

c++拥有类、继承、虚机制、重载、名称空间等,相同名字的函数,可能参数列表不同,为了支持这些复杂的特性,发明了符号修饰和符号改变。

aa.cpp文件代码如下:

int f(void)

{

return 1;

}

int f(int x)

{

return 0;

}

int main(int argc, char **argv)

{

int i = f();

int j = f(1);

return 0;

}

Windows平台运行结果如下:

Linux平台运行结果如下:

4、extern “C”

vs中默认.cpp文件用c++方式编译,.c文件用c方式编译。如果遇到混合编程的话,就需要用到extern "C"来设定编译方式。

新建aa.h文件:

#ifdef __cplusplus

extern "C" int f(int x);

#else

int f(int x);

#endif

__cplusplus是cpp中自定义的宏,如果是cpp文件,则会执行extern “C”,用C的方式编译f函数。

aa.cpp文件代码:

#include "aa.h"

int f(int x)

{

return 0;

}

int main(int argc, char **argv)

{

int j = f(1);

return 0;

}

执行结果:

2025-11-02 20:41:40
友情链接