其实在网上关于这个问题已经讨论很多了,但是大多都是重复的,确实讲解的很详细,还指出了怎么用是错误的,本来记忆就不怎么样,所以对于记忆这些错误的用法更是讨厌,还不如记忆一种通用的而且比较规范、代码阅读起来比较舒适的方法,下面我们开始吧!!!
C、C++密不可分,平时使用更多的是C,但有时候却少不了C++,而且是C、C++混搭(混合编程)在一起的,比如,RTP视频传输,live555多媒体播放等都是C++下的,他需要调用JRTPLIB库,再比如,我那邮件发送,我也用C++写的,定义了一个Email对象,包含了成员:收发邮件地址,用户名,密码等,以及方法:邮件头、Base64编码和邮件发送这些操作,很好用,所以,很多时候,C++还是蛮不错的。。。。但,*.c与*.cpp文件混搭在一起,不是那么的简单,。
一、extern“C”的作用(最重点)
1. extern "C"的真实目的是实现类C和C++的混合编程。extern “C”是由C++提供的一个连接交换指定符号,用于告诉C++这段代码是C函数。extern “C”后面的函数不使用的C++的名字修饰,而是用C。这是因为C++编译后库中函数名会变得很长,与C生成的不一致,造成C++不能直接调用C函数。
2.C++语言支持函数重载,C语言不支持函数重载。函数被C++编译后在库中的名字与C语言的不同。假设某个函数的原型为:void foo(int x, int y);该函数被C编译器编译后在库中的名字为_foo,而C++编译器则会产生像_foo_int_int之类的名字。C++提供了C连接交换指定符号extern“C”来解决名字匹配问题。
3.被extern "C"限定的函数或变量是extern类型的;extern是C/C++语言中表明函数和全局变量作用范围(可见性)的关键字,该关键字告诉编译器,其声明的函数和变量可以在本模块或其它模块中使用。被extern "C"修饰的变量和函数是按照C语言方式编译和连接的。
4.与extern对应的关键字是static,被它修饰的全局变量和函数只能在本模块中使用。因此,一个函数或变量只可能被本模块使用时,其不可能被extern “C”修饰。
二、extern“C”与__cplusplus
#ifdef __cplusplus
extern "C" {
#endif
#ifdef __cplusplus
}
#endif
Cplusplus(C plus plus)即"C++",用于C++文档的头文件中,上面代码的意思是:如果是C++文件(*.cpp)后缀,则使用extern “C”,在C++项目中应用的非常广泛。即使用gcc编译器编译,函数名为C类型如_foo。个人认为,搞懂了这两个关键字,尤其是理解extern "C"
extern "C" 是为了C与C++混合编程而设立的关键字,假如你已经知道了关于extern "C" 的一些使用方法,想很快掌握使用策略,下面从两个角度说明:
1)在C++程序中调用C程序,比如在CPP文件中使用C文件的某一个函数,那么可以肯定的是所使用的函数肯定是按照C语言的编译方式编译,那么仅仅通告CPP文件按照C语言调用函数的方式调用即可,而且不用再重新编译C函数,在函数所在头文件中添加extern "C"关键字,将这个头文件包含到CPP文件即可。也就是如下所示:
#ifdef __cplusplus
extern "C" {
#endif
/*... 函数声明*/
#ifdef __cplusplus
}
#endif
稍微举例说明一下:
// cheader.h
#ifndef _C_HEADER_
#define _C_HEADER_
#ifdef __cplusplus
extern "C" {
#endif
#include <stdio.h>
#include <stdlib.h>
int add(int a,int b);
#ifdef __cplusplus
}
#endif
#endif
// cfunc.c
//#include "header.h"
int add(int a,int b)
{
return a+b;
}
//main.cpp
#include <iostream>
#include "header.h"
using namespace std;
int main()
{
int a,b=0;
b= add(2,3);
cout<<b<<endl;
return 0;
}
由于.c文件中的函数就是按照C语言编译方式进行编译的,所以不包括头文件也是可以的,但是在头文件声明的时候必须进行说明,因为在CPP文件中包括的这个头文件会按照C语言的方式查找函数,不然就会按照C++的方式查找函数add
2)在C程序中使用CPP编译的函数,这样需要重新编译函数库,在函数声明的头文件中也是如上声明,然后再函数所在的CPP文件添加上述头文件,直接编译即可,这个时候虽说在CPP文件编译,但是是安装C语言的方式编译,在C文件中同样添加上述头文件即可。
稍微举例说明一下:
// cheader.h头文件
#ifndef _C_HEADER_
#define _C_HEADER_
#ifdef __cplusplus
extern "C" {
#endif
#include <stdio.h>
#include <stdlib.h>
int sub(int a,int b);
#ifdef __cplusplus
}
#endif
#endif
//cppsub.cpp
#include "header.h"
int sub(int a,int b)
{
return a-b;
}
/*但是如果将头文件的那一行注释掉,也会在连接时出错,因为在头文件中已经说明使用C语言的方式编译,但是不说明这一点,会使用C++编译方式进行
如果不想使用头文件,那么可以将int sub(int a,int b) 换为 extern "C" int sub(int a,int b) ,但是extern "C"在.c文件时不可以出现*/
//cmain.c
#include "header.h"
int main()
{
int a=0,b=0;
b = sub(2,3);
printf("b is %d\r\n",a,b);
return 0;
}
//C++头文件 cppExample.h
#ifndef CPP_EXAMPLE_H
#define CPP_EXAMPLE_H
extern "C" int add( int x, int y );
#endif
//C++实现文件 cppExample.cpp
#include "cppExample.h"
int add( int x, int y )
{
return x + y;
}
/* C实现文件 cFile.c
/* 这样会编译出错:#include "cExample.h" */
extern int add( int x, int y );
int main( int argc, char* argv[] )
{
add( 2, 3 );
return 0;
}
#define CPP_EXAMPLE_H
int add( int x, int y );
#endif
错误的原因在于在C语言中没有关键字 extern “C”
(PS:有的人会单独使用extern "C" 来修饰某个函数,我觉得不是很好看,特别是在头文件中不能这么使用,因为在C文件中不能出现这样的关键字,所以最好使用最后介绍的条件编译 在一定条件下才使用 extern "C")