最近在阅读libevent的源码,学到了不少东西,兼容C++的C头文件书写方式就是其中之一。
一 书写方式
下面是event.h文件的源码:
#ifndef _EVENT_H_
#define _EVENT_H_
#ifdef __cplusplus
extern "C" {
#endif
#include <event2/event-config.h>
#ifdef _EVENT_HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#ifdef _EVENT_HAVE_SYS_TIME_H
#include <sys/time.h>
#endif
#ifdef _EVENT_HAVE_STDINT_H
#include <stdint.h>
#endif
#include <stdarg.h>
/* For int types. */
#include <evutil.h>
#ifdef WIN32
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <winsock2.h>
#include <windows.h>
#undef WIN32_LEAN_AND_MEAN
typedef unsigned char u_char;
typedef unsigned short u_short;
#endif
#include <event2/event_struct.h>
#include <event2/event.h>
#include <event2/event_compat.h>
#include <event2/buffer.h>
#include <event2/buffer_compat.h>
#include <event2/bufferevent.h>
#include <event2/bufferevent_struct.h>
#include <event2/bufferevent_compat.h>
#include <event2/tag.h>
#include <event2/tag_compat.h>
#ifdef __cplusplus
}
#endif
#endif /* _EVENT_H_ */
可以看到,为了兼容C++,作了如下处理:
#ifdef __cplusplus
extern "C" {
#endif
// 需要包含的头文件
#ifdef __cplusplus
}
#endif
二 理解
重点来看extern "C"。
extern是C/C++语言中表明函数和全局变量作用范围(可见性)的关键字,该关键字告诉编译器,其声明的函数和变量可以在本模块或其它模块中使用。如:
extern int a;
通常,在模块的头文件中对本模块提供给其它模块引用的函数和全局变量以关键字extern声明。
与extern对应的关键字是static,被它修饰的全局变量和函数只能在本模块中使用。
一个函数或变量只可能被本模块使用时,其不可能被extern “C”修饰。
被extern "C"修饰的变量和函数是按照C语言方式编译和连接的;
三 C++和C语言编译的区别
假如有函数:
void fun(int x, int y){
return x + y
}
我们分别使用C和C++方式编译得到的结果如下:
C:
C++:
可以看到,除了文件名之外,编译之后的代码是一模一样。
这是因为C++为了支持函数重载,在函数名中加入了参数返回值和参数列表信息。
参数列表对应关系如下:
int->i,long->l,char->c,string->Ss
因为函数还有作用域信息,所以C++中函数编译之后对应的名字有如下规律:
作用域+返回类型+函数名+参数列表