C++初阶第二篇——初始C++(详细讲解extern “C”)

Posted 呆呆兽学编程

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C++初阶第二篇——初始C++(详细讲解extern “C”)相关的知识,希望对你有一定的参考价值。

⭐️今天·这篇博客我要来和大家一起聊一聊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++文件中。喜欢的话,欢迎大家点赞支持和收藏~

以上是关于C++初阶第二篇——初始C++(详细讲解extern “C”)的主要内容,如果未能解决你的问题,请参考以下文章

C++初阶第十二篇—stack和queue(stack和queue的常见接口的用法与介绍+priority_queue+容器适配器+仿函数+模拟实现)

C++初阶第三篇——初始C++(引用+内敛函数+auto关键字+范围for循环)

C++初阶第六篇——类和对象(下)(初始化列表+explicit关键字+static成员+友元+内部类)

数据结构初阶第二篇——顺序表(实现+动图演示)[建议收藏]

C++初阶第八篇——模板初阶(泛型编程+函数模板+类模板)

C++初阶第十一篇——list(list常见接口的用法与介绍+list的模拟实现+list迭代器原理)