⭐️今天·这篇博客我要来和大家一起聊一聊C++中 “extern"C” 的用处和用法,希望对大家有所帮助。
⭐️博客代码已上传至gitee:https://gitee.com/byte-binxin/cpp-class-code/tree/master
🌏extern"C"是什么?
🍤有时候在C++工程中可能需要将某些函数按照C的风格来编译,在函数前加extern “C”,意思是告诉编译器,将该函数按照C语言规则来编译。
🌏如何使用?
🍆为了让大家更好地理解extern “C”,我来给大家用静态库的方式演示一下
🌲首先创建一个静态库
🍅以“vs2019”为例,我们把自己之前写的栈放到静态库里,先创建一个空项目,然后打开项目属性,把.exe的属性改成静态库的属性就好了,如下图:
最后再编译运行一下,静态库就生成了。
这是一个c的静态库;
🌲演示C++调用C的静态库
🍅以leedcode上面的有效括号这一题为例子,给大家演示一下。(模拟实现的栈在数据结构初阶的博客中有写过,可以参考这里——栈和队列)
调用静态库之前,我们要进行一个附加库目录和附加依赖项的操作,分别如下:
第一步:
第二步:
这样一来,静态库就完全地用起来了。
下面是用C++项目调用C的静态库,没有使用extern “C”,我们看会发生什么。
#include <iostream>
using namespace std;
#include "../../Stacklib/Stacklib/Stack.h"
bool isValid(char* s) {
Stack st;
StackInit(&st);
int i = 0;
while (s[i])
{
//左括号就插入
if (s[i] == '(')
{
StackPush(&st, ')');
}
else if (s[i] == '{')
{
StackPush(&st, '}');
}
else if (s[i] == '[')
{
StackPush(&st, ']');
}
else
{
//if (st.empty())//栈里为空,且现在为右括号就直接返回false
// return false;
if (!StackEmpty(&st) && StackTop(&st) == s[i])
{
StackPop(&st);
}
else
{
StackDestroy(&st);
return false;
}
}
i++;
}
if (StackEmpty(&st))
{
StackDestroy(&st);
return true;
}
else
{
StackDestroy(&st);
return false;
}
}
int main()
{
char str[] = "()[]{}";
printf("%d\n", isValid(str));
return 0;
}
结果如下:
显然,在没有使用extern “C”的情况下,直接调用C的静态库编译器会报错,根本不认识静态库中的标识符。所以我们在项目前面使用extern “C”,如下:
// 告诉C++编译器,extern "C"花括号里面的内容是C编译器编译的,按C的函数的命名规则去找,就可以链接上了
extern "C"
{
#include "../../Stacklib/Stacklib/Stack.h"
}
⭐️ 这里就是告诉C++编译器,extern "C"花括号里面的内容是C编译器编译的,按C的函数的命名规则去找,就可以链接上,显然,代码很顺利地跑起来了。
🌲演示C调用C++的静态库
首先我们把先前C++的项目后缀改成 .c,把静态库的c文件改成cpp,我们试着反着来调用,会发生什么。
运行结果如下:
显然,c编译器不认识静态库中的函数。
下面是静态库头文件的内容:
#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <assert.h>
typedef int STDatatype;
typedef struct Stack
{
STDatatype* a;
int top;
int capcaity;
}Stack;
//初始化栈
void StackInit(Stack* ps);
//销毁栈
void StackDestroy(Stack* ps);
//压栈
void StackPush(Stack* ps, STDatatype x);
//出栈
void StackPop(Stack* ps);
//取出栈顶元素
STDatatype StackTop(Stack* ps);
//栈的大小
int StackSize(Stack* ps);
//判断栈是否为空
bool StackEmpty(Stack* ps);
我们需要对其进行修改,让这些函数以C的方式去编译,修改后如下(两种方法):
// C++静态库,就会按照C的函数的命名规则去处理以下函数
// 第一种方法
#ifdef __cplusplus
#define EXTERN_C extern "C"
#else
#define EXTERN_C
#endif
//初始化栈
EXTERN_C void StackInit(Stack* ps);
//销毁栈
EXTERN_C void StackDestroy(Stack* ps);
//压栈
EXTERN_C void StackPush(Stack* ps, STDatatype x);
//出栈
EXTERN_C void StackPop(Stack* ps);
//取出栈顶元素
EXTERN_C STDatatype StackTop(Stack* ps);
//栈的大小
EXTERN_C int StackSize(Stack* ps);
//判断栈是否为空
EXTERN_C bool StackEmpty(Stack* ps);
//第二种方法
#ifdef __cplusplus
extern "C"
{
#endif
//初始化栈
void StackInit(Stack* ps);
//销毁栈
void StackDestroy(Stack* ps);
//压栈
void StackPush(Stack* ps, STDatatype x);
//出栈
void StackPop(Stack* ps);
//取出栈顶元素
STDatatype StackTop(Stack* ps);
//栈的大小
int StackSize(Stack* ps);
//判断栈是否为空
bool StackEmpty(Stack* ps);
#ifdef __cplusplus
}
#endif
🍆其中 __cplusplus这个宏是在cpp文件中就会有所定义,所以如果定义了这个宏,我们就定义
EXTERN_C extern “C”,否则就定义为空。
这样操作,代码也成功地跑起来了:
🌐总结
这篇博客就给大家介绍了一下如何利用extern “C”来做到C++和C之间的相互调用,总之,extern “C”总是出现在C++文件中。喜欢的话,欢迎大家点赞支持和收藏~