以下是与Chatgpt的对话记录
1. extern "C"的作用是什么?
extern “C” 是一个关键字组合,用于告诉编译器按照 C 语言的约定来处理函数或变量的名称和调用方式。在 C++ 中,函数名和变量名由于支持函数重载特性而不同于 C 语言,它们被编译器进行了一定的名称修饰(Name Mangling)。因此,如果需要使用 C 语言编写的函数库,就需要使用 extern “C” 声明来显式地指定 C 语言的调用约定,以保证 C++ 能够正确地使用这些函数。
例如,在 C++ 中调用一个 C 函数:
extern "C" int add(int a, int b); // 声明
int main()
{
int sum = add(1, 2); // 调用
return 0;
}
通过 extern “C” 声明,编译器会按照 C 语言的传统方式来调用函数。这样就可以在 C++ 中使用 C 函数库,而无需考虑 C++ 名称修饰的问题。
2. 如何在.C中调用.C++的函数?
在 C 中调用 C++ 的函数时,由于 C++ 支持函数重载和命名空间(namespace)等特性,C++ 编译器会对函数名称进行修饰,导致无法直接使用 C 接口的函数。
因此,需要通过 extern “C” 关键字组合来告诉编译器按照 C 语言的方式对函数进行处理。具体地,需要在 C++ 函数的定义以及声明前添加 extern “C” 关键字组合,这样编译器就会生成不带名称修饰的符号名称。
例如,在 C++ 中定义如下的函数:
// add.h 文件
#ifndef ADD_H
#define ADD_H
#ifdef __cplusplus
extern "C"
#endif
int add(int a, int b);
#endif
// add.cpp 文件
#include "add.h"
int add(int a, int b)
{
return a + b;
}
其中,#ifdef __cplusplus 和 #endif 之间的代码用于保证在 C++ 中包含该头文件时,会自动加入 extern “C” 的声明。在 C 文件中使用该头文件时,则不会自动加入 extern “C” 声明,需要手动添加。
然后,在 C 中使用该函数时,只需包含 add.h 头文件即可:
// main.c 文件
#include <stdio.h>
#include "add.h"
int main()
{
int sum = add(1, 2);
printf("sum = %d\n", sum);
return 0;
}
这样,就可以在 C 程序中使用 C++ 的函数了。
3. 重载函数如何在.C中调用
对于 C++ 中的函数重载,可以使用 extern “C” 关键字组合来进行处理。为了区分不同版本的函数,需要在函数名称后面添加参数类型和个数的信息。
例如,对于以下的 C++ 函数:
// add.h 文件
#ifndef ADD_H
#define ADD_H
#ifdef __cplusplus
extern "C"
#endif
int add(int a, int b);
#ifdef __cplusplus
extern "C"
#endif
double add(double a, double b);
#ifdef __cplusplus
extern "C"
#endif
float add(float a, float b);
#endif
// add.cpp 文件
#include "add.h"
int add(int a, int b)
{
return a + b;
}
double add(double a, double b)
{
return a + b;
}
float add(float a, float b)
{
return a + b;
}
其中,每个版本的函数名称都一样,但参数类型和个数不同,因此需要通过添加外部链接指示器(External Linkage Specifier)来区分它们。在 Windows 平台上,通常使用以下的命名约定:
无符号修饰:_stdcall
有符号修饰:__cdecl
因此,在 add.h 中添加以下的声明:
// add.h 文件
#ifndef ADD_H
#define ADD_H
#ifdef __cplusplus
extern "C"
#endif
int __cdecl add_int(int a, int b);
#ifdef __cplusplus
extern "C"
#endif
double __cdecl add_double(double a, double b);
#ifdef __cplusplus
extern "C"
#endif
float __cdecl add_float(float a, float b);
#endif
在 add.cpp 中,定义这三个函数的实现:
// add.cpp 文件
#include "add.h"
int __cdecl add_int(int a, int b)
{
return a + b;
}
double __cdecl add_double(double a, double b)
{
return a + b;
}
float __cdecl add_float(float a, float b)
{
return a + b;
}
这样,在 C++ 中定义 extern “C” 标记并使用特殊的命名约定,就可以防止 C++ 编译器对函数名进行修饰,使得其名称与 C 语言兼容。在 C 中调用该函数时,只需要通过 add.h 头文件来包含这三个函数的声明即可。
注意,这种方法只适用于已知函数原型的情况下,而在不了解函数原型的情况下,还需要使用其他技术和工具来处理。