C语言与C++ 相互调用
想学好编程的小菜鸟 人气:4前言
extern “c”的作用可以实现c语言和c++相互调用。
1.当我们写c语言代码,要调用c++代码时,可以将c++的类型配置为静态库,然后直接调用头文件。
2.当我们写c++代码,要调用c代码时,可以将c的类型配置为静态库,然后直接调用头文件。
由于c++支持函数重载,而c语言不支持函数重载,c语言和c++的函数名修饰规则有所不同,所以在链接的时候就C和C++之间无法找到对应的函数地址。这时候就要引入extern “C”了。
如果是C调用C项目或是C++调用C++项目就不需要使用extern "C"了。
下面介绍的是不同项目之间的调用。
1.在C++项目中调用C的静态库时,告诉C++编译器,extern "C"{}里面的函数是C编译器编译的,链接的时候用C的函数名规则去找,就可以链接上。
2.在C项目中调用C++的静态库时,同样告诉C++编译器,extern "C"{}里面的函数要用C语言的修饰规则修饰。
下面我们通过代码来了演示,实验环境:VS2019。
一、C++项目调用C的静态库
我们先将写好的C程序配置成.lib的静态库:
此时该静态库的debug目录下就有.lib的静态库
然后在需要调用库的C++项目中,引入静态库:
将附加库目录的路径设置为配置好的静态库的debug路径下。
然后在链接器的输入下添加 c的lib.lib;(创建的项目名.lib)
调用静态库的C++代码:
其中include内的 ..是跳转到上一级目录。
#include <iostream> using namespace std; // C++项目 // 告诉C++编译器,extern "C"{}里面的函数是C编译器编译的,链接的时候用C的函数名规则去找,就可以链接上 extern "C" { #include "../c的lib/Stack.h" } bool isValid(const char * s){ ST st = { 0 }; StackInit(&st); while (*s) { if (*s == '(' || *s == '{' || *s == '[') { StackPush(&st, *s); ++s; } else { // 遇到右括号了,但是栈里面没有数据,说明 // 前面没有左括号,不匹配,返回false if (StackEmpty(&st)) { StackDestroy(&st); return false; } STDataType top = StackTop(&st); StackPop(&st); if ((*s == '}' && top != '{') || (*s == ']' && top != '[') || (*s == ')' && top != '(')) { StackDestroy(&st); return false; } else { ++s; } } } // 如果栈不是空,说有栈中还有左括号未出 // 没有匹配,返回是false bool ret = StackEmpty(&st); StackDestroy(&st); return ret; } int main() { cout << isValid("{[]}") << endl; cout << isValid("([)]") << endl; return 0; }
配置静态库的c代码:
Stcak.h
#pragma once #include <stdio.h> #include <stdlib.h> #include <assert.h> #include <stdbool.h> typedef int STDataType; typedef struct Stack { STDataType* a; int top; int capacity; }ST; void StackInit(ST* ps); void StackDestroy(ST* ps); void StackPush(ST* ps, STDataType x); void StackPop(ST* ps); STDataType StackTop(ST* ps); int StackSize(ST* ps); bool StackEmpty(ST* ps);
Stack.c
#define _CRT_SECURE_NO_WARNINGS 1 #include "Stack.h" void StackInit(ST* ps) { assert(ps); ps->a = NULL; ps->top = 0; // ps->top = -1; ps->capacity = 0; } void StackDestroy(ST* ps) { assert(ps); free(ps->a); ps->a = NULL; ps->capacity = ps->top = 0; } void StackPush(ST* ps, STDataType x) { assert(ps); if (ps->top == ps->capacity) { int newCapacity = ps->capacity == 0 ? 4 : ps->capacity * 2; STDataType* tmp = (STDataType*)realloc(ps->a, sizeof(STDataType) * newCapacity); if (tmp == NULL) { printf("realloc fail\n"); exit(-1); } ps->a = tmp; ps->capacity = newCapacity; } ps->a[ps->top] = x; ps->top++; } void StackPop(ST* ps) { assert(ps); assert(!StackEmpty(ps)); ps->top--; } STDataType StackTop(ST* ps) { assert(ps); assert(!StackEmpty(ps)); return ps->a[ps->top - 1]; } int StackSize(ST* ps) { assert(ps); return ps->top; } bool StackEmpty(ST* ps) { assert(ps); /*if (ps->top == 0) { return true; } else { return false; }*/ return ps->top == 0; }
二、C项目调用C++的静态库
实现方法与上面类似。只需要将上面步骤的.cpp与.c文件后缀互换,然后通过条件编译,将C++静态库中的头文件的函数用extern "C"作用:
#pragma once #include <stdio.h> #include <stdlib.h> #include <assert.h> #include <stdbool.h> typedef int STDataType; typedef struct Stack { STDataType* a; int top; int capacity; }ST; //void StackInit(ST* ps); //void StackDestroy(ST* ps); //void StackPush(ST* ps, STDataType x); //void StackPop(ST* ps); //STDataType StackTop(ST* ps); //int StackSize(ST* ps); //bool StackEmpty(ST* ps); #ifdef __cplusplus extern "C" { #endif void StackInit(ST* ps); void StackDestroy(ST* ps); void StackPush(ST* ps, STDataType x); void StackPop(ST* ps); STDataType StackTop(ST* ps); int StackSize(ST* ps); bool StackEmpty(ST* ps); #ifdef __cplusplus } #endif
其中__cplusplus是c++中定义好的宏。所以在c++中就会展开extern "C"{},告诉编译器按照c语言的函数修饰规则修饰,而c项目调用头文件时,就没有__cplusplus这个宏就不会展开extern "C"{},只会将修饰好的函数声明展开。
还有另一种条件编译:
#ifdef __cplusplus #define E extern "C" #else #defien E #endif E void StackInit(ST* ps); E void StackDestroy(ST* ps); E void StackPush(ST* ps, STDataType x); E void StackPop(ST* ps); E STDataType StackTop(ST* ps); E int StackSize(ST* ps); E bool StackEmpty(ST* ps);
然后在C项目中调用头文件#include "../c的lib/Stack.h",(这是调用的头文件在我的电脑中的存放路径,大家调用的时候跳转到自己存放头文件的路径即可)因为C中没有定义__cplusplus,这样C项目调用时,将E替换为空 ,直接展开函数声明。
三、总结
1️⃣通过extern "C",我们可以实现C项目调C++的库,C++项目调C的库。不需要源码,只需要静态库和头文件就可以实现功能。
2️⃣在多人协作时尤为方便,只需要将写好的代码配置成.lib的静态库,然后将头文件一起打包发给对方,对方在不知道具体的源码和函数的实现下,只需要知道函数的功能就可以直接调用,也加强的多人协作之间的保密性
3️⃣因为extern "C"只在C++中 起作用,所以不管是调用C的库还是C++的库,extern "C"都只在C++中处理。
加载全部内容