C/C++混合编程--extern “C” 使用方法详解

其实在网上关于这个问题已经讨论很多了,但是大多都是重复的,确实讲解的很详细,还指出了怎么用是错误的,本来记忆就不怎么样,所以对于记忆这些错误的用法更是讨厌,还不如记忆一种通用的而且比较规范、代码阅读起来比较舒适的方法,下面我们开始吧!!!

CC++密不可分,平时使用更多的是C,但有时候却少不了C++,而且是CC++混搭(混合编程)在一起的,比如,RTP视频传输,live555多媒体播放等都是C++下的,他需要调用JRTPLIB库,再比如,我那邮件发送,我也用C++写的,定义了一个Email对象,包含了成员:收发邮件地址,用户名,密码等,以及方法:邮件头、Base64编码和邮件发送这些操作,很好用,所以,很多时候,C++还是蛮不错的。。。。但,*.c*.cpp文件混搭在一起,不是那么的简单,。

 

一、extern“C”的作用(最重点)

    1. extern "C"的真实目的是实现类CC++的混合编程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类型的;externC/C++语言中表明函数和全局变量作用范围(可见性)的关键字,该关键字告诉编译器,其声明的函数和变量可以在本模块或其它模块中使用。被extern "C"修饰的变量和函数是按照C语言方式编译和连接的。   

     4.与extern对应的关键字是static,被它修饰的全局变量和函数只能在本模块中使用。因此,一个函数或变量只可能被本模块使用时,其不可能被extern “C”修饰。

 

二、extern“C”__cplusplus

#ifdef __cplusplus

       extern "C" {

       #endif

 

       #ifdef __cplusplus

       }

       #endif

    CplusplusC 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;
}
 
note: 如果 cppEample.h 改成:
#ifndef CPP_EXAMPLE_H
#define CPP_EXAMPLE_H
 
#ifdef  __cplusplus
extern "C" {
#endif

int add( int x, int y );
#ifdef __cplusplus
}
#endif

#endif
 
则在 C 文件中 #include "cExample.h" 就不会报错了.
 
总之, 无论写 c 还是 c++头文件,只要是想以后混合编程,就最好加上
 
#ifdef  __cplusplus
extern "C" {
#endif
 
/**** some declaration or so *****/
 
#ifdef  __cplusplus
    }
#endif  /* end of __cplusplus */
错误的原因在于在C语言中没有关键字 extern “C”
(PS:有的人会单独使用extern "C" 来修饰某个函数,我觉得不是很好看,特别是在头文件中不能这么使用,因为在C文件中不能出现这样的关键字,所以最好使用最后介绍的条件编译 在一定条件下才使用 extern "C")











   

你可能感兴趣的:(C++,c)