30.externC的用法
30.externC的用法
为了能够正确地在C++代码中调用C语言的代码:在程序中加上extern "C"后,相当于告诉编译器这部分代码是C语言写的,因此要按照C语言进行编译,而不是C++;
哪些情况下使用extern "C":
(1)C++代码中调用C语言代码;
(2)在C++中的头文件中使用;
(3)在多个人协同开发时,可能有人擅长C语言,而有人擅长C++;
总结出如下形式:
(1)C++调用C函数:
当你有一个 C 函数在一个库或源文件中,并希望在 C++ 代码中调用它时,你需要确保 C++ 编译器知道这个函数具有 C 链接约定,而不是 C++ 链接约定。为了实现这一点,你会使用 extern "C"
。
下面是一个完整的示例来展示如何做到这一点:
①C 代码 (c_functions.c
):
#include <stdio.h>
void c_function() {
printf("This is a C function.\n");
}
②C 头文件 (c_functions.h
):
#ifndef C_FUNCTIONS_H
#define C_FUNCTIONS_H
// 用于 C++ 中
#ifdef __cplusplus
extern "C" {
#endif
void c_function();
#ifdef __cplusplus
}
#endif
#endif // C_FUNCTIONS_H
好的,这是一个典型的C语言的头文件,用于保证C函数可以被C++代码调用。我会逐行为您解释。
#ifndef C_FUNCTIONS_H
这是一个预处理指令,检查C_FUNCTIONS_H
是否已定义。如果尚未定义,代码将继续执行,直到遇到与此匹配的#endif
。这是所谓的“包含保护”或“头文件保护”,用于确保头文件在一个编译单位中只被包含一次。这可以避免因重复包含而引起的重复定义。
#define C_FUNCTIONS_H
这里定义了C_FUNCTIONS_H
,因此下次再包含这个头文件时,#ifndef
将检查到它已经定义,从而防止头文件的内容被重复包含。
// 用于 C++ 中
这是一个注释,表示以下的代码是为C++设计的。
#ifdef __cplusplus
这是一个预处理指令,检查是否定义了__cplusplus
宏。__cplusplus
是一个内置的宏,在C++代码中被自动定义。这样,只有在C++中编译时,它下面的代码才会被包括进来。
extern "C" {
这告诉C++编译器以下的代码是按C语言的方式进行链接。C++因为其函数重载的特性,会对函数名进行“名称修饰”(name mangling),而C没有这个特性。当我们在C++中调用C函数时,需要告诉C++编译器不要对这些函数名进行名称修饰。
void c_function();
这是一个C函数的声明。
#ifdef __cplusplus
}
#endif
这些代码结束了extern "C"
块。如果在C++环境中,这段代码将关闭extern "C"
声明,意味着之后的代码不再需要按C语言的方式链接。
#endif // C_FUNCTIONS_H
这是与最初的#ifndef C_FUNCTIONS_H
相匹配的#endif
,标记着“包含保护”的结束。
总结:这个头文件的主要目的是确保C函数可以在C++中被正确调用,同时也避免头文件被重复包含。
③C++ 代码 (main.cpp
):
#include <iostream>
#include "c_functions.h"
int main()
{
std::cout << "Calling from C++ code." << std::endl;
c_function();
return 0;
}
当你要编译这些代码时,你需要确保同时编译 C 和 C++ 源文件。例如,使用 gcc
和 g++
:
gcc -c c_functions.c
g++ main.cpp c_functions.o -o my_program
在这个例子中,我们在 C 头文件中使用 extern "C"
来告诉 C++ 编译器 c_function
使用的是 C 链接约定。这确保了当我们在 C++ 代码中调用 c_function
时,链接器能够找到正确的函数,因为它的名字没有经过 C++ 的名字改编(name mangling)。
(2)在C++中的头文件中使用;
①在CppClass.h
中,您应该仅声明C函数。包含它的C头文件可能更加合适,而不是直接在C++头文件中声明。
②我们不应该在C的源文件中包含C++的头文件。
让我给您一个修正后的例子。
首先是C函数的声明和定义:
C语言的头文件 (c_functions.h
):
// c_functions.h
#ifndef C_FUNCTIONS_H
#define C_FUNCTIONS_H
void my_c_function();
#endif // C_FUNCTIONS_H
C语言的实现文件 (c_functions.c
):
// c_functions.c
#include "c_functions.h"
#include <stdio.h>
void my_c_function() {
// 实现部分,例如打印一个消息
printf("This is a function written in C.\n");
}
然后是C++类的声明和定义:
C++的头文件 (CppClass.h
):
// CppClass.h
#ifndef CPPCLASS_H
#define CPPCLASS_H
#ifdef __cplusplus
extern "C" {
#include "c_functions.h"
}
#endif
class CppClass {
public:
void callCFunction();
};
#endif // CPPCLASS_H
C++的实现文件 (CppClass.cpp
):
// CppClass.cpp
#include "CppClass.h"
#include <iostream>
void CppClass::callCFunction() {
std::cout << "Calling a C function from C++ method:" << std::endl;
my_c_function();
}
最后是主文件:
主C++源文件 (main.cpp
):
// main.cpp
#include <iostream>
#include "CppClass.h"
int main() {
CppClass obj;
obj.callCFunction(); // 在C++类方法中调用C函数
return 0;
}
现在,C++的头文件CppClass.h
使用extern "C"
将C的头文件c_functions.h
包围起来,这确保了在C++代码中正确地调用C函数。
(3)一些其他用法
①变量的调用
在extern1.cpp中定义一个全局变量:
int a = 12;
在externMain.cpp中:
#include <iostream>
using namespace std;
int a;
int main()
{
cout << a << endl;
system("pause");
return 0;
}
这样编译就会出现错误:
这时需要在externMain.cpp中,在int a前面添加关键字extern
extern int a;
这时便能成功打印出来变量a的值了,注意变量前面的类型不能省略,否则编译器报错:缺少类型说明符
②函数的调用
在extern1.cpp中,定义一个函数:
#include <iostream>
using namespace std;
void fun()
{
cout << "helloworld" << endl;
}
在externMain.cpp中调用该函数:
#include <iostream>
using namespace std;
int main()
{
fun();
system("pause");
return 0;
}
如果这样直接编译的话,会报错:
需要在函数使用前进行声明:
#include <iostream>
using namespace std;
void fun();
int main()
{
fun();
system("pause");
return 0;
}
如果我们在函数声明的地方加上extern关键字,程序也是可以运行的:
extern void fun();
对于外部函数,extern可以省略,但对于外部变量,extern就不能被省略