赞
踩
有时候在C++的工程中可能需要将某些函数按照C的风格来编译,在函数前加extern “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; }
这里与上面是非常类似的,可以通过把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; }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。