[坑]VS编译c/cpp文件,导出不同符号表

2021/06 17 22:06

MS VisualStudio默认情况下,后缀为c的文件,使用c样式导出符号表
后缀为cpp的文件,使用c++样式导出符号表;

所以在同一个工程中:

在a.cpp中实现:
void foo() {}
在b.c中使用:
void foo();
foo(); // error LNK2019: 无法解析的外部符号 _foo

或者

在a.c中实现:
void foo() {}
在b.cpp中使用:
void foo();
foo(); // LNK2019: 无法解析的外部符号 "void __cdecl foo(void)" (?foo@@YAXXZ)

所以在cpp中使用c函数,要使用 extern “C” { void foo(); } 去包一下;
但在c中使用cpp的函数,还不知道如何引入…


1、C编译器的函数名修饰规则 


__cdecl调用约定(c标准调用约定):仅在输出函数名前加上一个下划线前缀,例如_sum。

__stdcall调用约定(windows标准调用约定):编译器和链接器会在输出函数名前加上一个下划线前缀,函数名后面加上一个“@”符号和其参数的字节数,例如 _sum@number。

__fastcall调用约定(快速调用约定):在输出函数名前加上一个“@”符号,后面也是一个“@”符号和其参数的字节数,例如 @sum@number。

2、 C++编译器的函数名修饰规则 

对于__stdcall方式,参数表的开始标识是“@@YG”,对于__cdecl方式则是“@@YA”,对于 __fastcall方式则是“@@YI”。

符号生成规则

_cdecl调用约定:“?”+函数名+参数表的开始标识 “@@YA” + 函数返回类型代号+参数类型代号 +结束标识“@Z”或“Z”(无参数)。

_stdcall调用约定:“?”+函数名+参数表的开始标识“@@YG”+函数返回类型代号+参数类型代号 +结束标识“@Z”或“Z”(无参数)。

_fastcal调用约定:“?”+函数名+参数表的开始标识 “@@YI”+ 函数返回类型代号+参数类型代号 +结束标识“@Z”或“Z”(无参数)。

参数表的拼写代号

XDEFHIJKMN_NUPA+PB+
voidcharunsignedcharshortintunsignedintlongunsignedlongfloatdoubleboolstruct指针+类型const指针+类型

_thiscall调用约定(类成员方法的约定):“?” +函数名+ “@”字符引导的类名+参数表的开始标识(函数性质决定)+ 函数返回类型代号+参数类型代号 +结束标识“@Z”或“Z”(无参数)。

参数表的开始标识:公有(public)成员函数的标识“@@QAE”,保护(protected)成员函数的标识“@@IAE”,私有(private)成员函数“@@AAE”;如果使用Const ,则对应的标识“@@QBE”,“@@IBE”,“@@ABE”。