C++基础知识之extern “C“的用法。

  • 概述

有时候在C++的工程中可能需要将某些函数按照C的风格来编译,在函数前加extern “C”,意思是告诉编译器,将该函数按照C语言规则来编译。这里通俗的讲就是,在C++的工程中我们可以包含一个头文件,调用一些用C语言格式写的函数。同样的在C的工程中我们也可以包含其它C++工程头文件,调用C++源文件中的函数。接下来就分别介绍这两种用法,和其中原理。

  • C++项目调用C文件的函数

我新建一个C++项目然后调用C写的栈这种数据结构为例来进行说明。新建一个C的项目命名位static base,从以前的栈的项目中复制头文件stack.h,里面是栈的建立,各种操作函数的声明,并且也复制源文件stack.c,里面就是头文件中各函数的实现,将这两个文件复制到刚新建的static base 工程下。
在这里插入图片描述
右击源文件添加现有项将stack.c添加进来,右击头文件添加现有项将stack.h添加进来。我们待会是要用C++项目来使用这里C写的栈。首先完成以上步骤后,我们要将static base这个项目改一下属性,以便后面用C++调用这里的函数。
在这里插入图片描述
右击图示位置选择属性到以下界面,将配置类型由应用程序改为静态库,就是变为由其他工程调用的库,这里最后将data base 编译成后缀为.lib的文件而不是可执行程序。
在这里插入图片描述
在这里插入图片描述
这就是现成的C的静态库,接下来我们新建一个C++的项目,在其中调用这个静态库,使用C文件中的函数,新建C++项目命名为test_12_2(随便命名),创建一个源文件命名test.cpp,我们就调用C中的函数在.cpp文件中完成一些简单的操作来练习extern "C"的用法。在test_12_2的项目中要调用static base中的函数也要对属性进行一些设置。
首先在属性,链接器,常规,附加库目录中点下拉箭头添加我们准备调用的静态库的路径,选中我们准备调用的项目static base下的Debug,因为我们刚刚在static base中编译生成的.lib文件就在Debug下。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
第二步,点击输入在附加依赖项栏中前面添加项目名加.lib后缀和分号,即static base.lib;
在这里插入图片描述
完成两步设置点应用加确定,一定要注意是在你准备调用的静态库项目中将属性改成静态库.lib这里是static base,在你准备操作调用其他静态库项目的项目中改以上两处位置属性,这里是test_12_2
下面就可以在test_12_2项目中在C++中用到C写的栈了,首先要用#include命令把另一个项目中的stack.h包含进来,要包含不在同一个项目中的头文件,就只能返回上一层路径去找。

#include"../../static base/stack.h"

这里. . 两个符号就是从test_12_2这一层再向上一层去找static base这个项目,在这个项目往下找到stack.h。
在.cpp中预处理时就会把stack.h给展开,这时本文要介绍的主角extern "C"就登场了。

extern "C"
{
#include"../../static base/stack.h"
}

展开后有了extern “C”,它就会告诉编译器下面范围内的函数按C语言的风格来编译,在链接环境按C的函数命名规则去相应文件符号表中找相应函数的地址。
下面是在.cpp中调用C的函数的测试代码和效果。

extern "C"
{
 #include"../../static base/stack.h"
}
#include<iostream>
using namespace std;
void print(int* a, int n)
{
	for (int i = 0; i < n; i++)
		printf("%d ",a[i]);
	printf("\n");
}
int main()
{
	Sta  N;
	stackinit(&N);
	stackpush(&N, 1);
	stackpush(&N, 2);
	stackpush(&N, 3);
	stackpush(&N, 4);
	stackpush(&N, 5);
	stackpop(&N);
	stackpop(&N);
	print(N.a, N.top);
	
	return 0;
}

在这里插入图片描述

  • C项目中调用C++文件格式的函数

这里与上面是非常类似的,可以通过把static base中的stack.c后缀改成.cpp,这就是C++格式的函数了,然后将test_12_2的test.cpp改成test.c,在这里调用static base中的函数,这就是在C的项目中调用C++的函数了。
这里的关键点是,在包含stack.h后test_12_2在C的格式下编译会出错,因为C是没有extern "C"的,它不认识这种语法,只有C++才认识,这里要用到条件编译。

#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#include<assert.h>

typedef int Datatype;
typedef struct stack
{
   Datatype* a;
   int top;
   int capacity;
}Sta;

#ifdef __cplusplus
extern "C"
{
#endif 
   void stackinit(Sta* st);   //栈的初始化
   void stackdestory(Sta* st);   //栈的销毁
   void stackpush(Sta* st, Datatype x);  //数据入栈
   void stackpop(Sta* st);            //数据出栈
   Datatype stacktop(Sta* st);     //获得栈顶数据
   int  stacksize(Sta* st);          //计算栈数据元素个数
   bool stackEmpty(Sta* st);     //栈为空返回真  否则返回假
#ifdef __cplusplus
}
#endif

现在是C++格式的栈,要在C项目中调用它。在static base 中编译,因为是C++格式下,有__cplusplus的标识符,所以这里的函数声明都会包含在extern "C"中,而在test_12_2中包含了stack.h,在这里C格式下展开后没有__cplusplus的标识符,条件编译为假,最后只会编译函数声明,extern "C"不会被编译,extern "C"就会告诉编译器这些函数按C的风格去编译和链接。还有另一种使用条件编译的方法使extern "C"在C++下编译,在C下不编译。

#ifdef __cplusplus
#define EXTERN_C  extern "C"
#else
#define EXTERN_C
#endif

EXTERN_C	void stackinit(Sta* st);   //栈的初始化
EXTERN_C	void stackdestory(Sta* st);   //栈的销毁
EXTERN_C	void stackpush(Sta* st, Datatype x);  //数据入栈
EXTERN_C	void stackpop(Sta* st);            //数据出栈
EXTERN_C	Datatype stacktop(Sta* st);     //获得栈顶数据
EXTERN_C	int  stacksize(Sta* st);          //计算栈数据元素个数
EXTERN_C	bool stackEmpty(Sta* st);     //栈为空返回真  否则返回假

测试代码和测试结果

#include"../../static base/stack.h"

void print(int* a, int n)
{
	for (int i = 0; i < n; i++)
		printf("%d ",a[i]);
	printf("\n");
}
int main()
{
	Sta  N;
	stackinit(&N);
	stackpush(&N, 1);
	stackpush(&N, 2);
	stackpush(&N, 3);
	stackpush(&N, 4);
	stackpush(&N, 5);
	print(N.a, N.top);
	
	return 0;
}

在这里插入图片描述

  • 14
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 10
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值