阅读任何一个开源代码项目,最好阅读前了解作者开发这个软件前制定的一些约定。例如,命名规范,代码排版风格等。Sofia-SIP也有类似的文档,可以访问这个网页了解详情:http://sofia-sip.sourceforge.net/refdocs/styleguide.html。这些是一些通用规范,但代码中还会有一些反复出现的宏或者其他有规律性的使用方式。如果阅读前也能熟悉它们,可以加快阅读代码的速度。
su_config.h
打开Sofia-SIP工程中任何一个头文件,几乎总能看到这样两条语句:
SOFIA_BEGIN_DECLS SOFIA_END_DECLS
这两句分别处于头文件的开始处和结尾处。它们在sofia-sip/su_config.h头文件中定义。
/* C++ linkage needs to know that types and declarations are C, not C++. */ #if defined(__cplusplus) /** Begin declarations in Sofia header files */ # define SOFIA_BEGIN_DECLS extern "C" { /** End declarations in Sofia header files */ # define SOFIA_END_DECLS } #else # define SOFIA_BEGIN_DECLS # define SOFIA_END_DECLS #endif
在C++编译器下,SOFIA_BEGIN_DECLS被扩展成“extern "C" {”,“SOFIA_END_DECLS”被扩展成“}”。合并在一块就是:
extern "C" { }
这就是我们通常在写C++的Dll时经常用到的方法,防止C++变更函数名称。如果在C编译器下,两个宏被替换成空什么都没有。因为Sofia-SIP库也会在C++编译器下编译,提供给C++代码调用,所以必须加上extern这句。但如果每个头文件都写下面的语句又显得太罗嗦和繁琐:
#if defined(__cplusplus) extern "C" { #endif ... #if defined(__cplusplus) } #endif
因此,Sofia-SIP的作者觉得采用定义宏的方式。这样,每个头文件只需写两条这样的语句即可,减少了工作量,代码整体排版也显得更清洁。
既然打开了su_confg.h头文件,那就看看它里面还有什么。里面机会都是整个项目范围内都会用到的宏定义。接着来了解SOFIAPUBFUN、SOFIAPUBVAR和SOFIACALL这三个宏。注释部分说明这些宏是为Win32平台编译链接而准备。因此,在开始处三个宏定义是为非Win32平台准备的,所以SOFIAPUBFUN和SOFIACALL的定义都是空,只有SOFIAPUBVAR可以扩展成extern。
/* ---------------------------------------------------------------------- */ /* Macros required by Win32 linkage */ /** SOFIAPUBFUN declares an exported function */ #define SOFIAPUBFUN /** SOFIAPUBVAR declares an exported variable */ #define SOFIAPUBVAR extern /** SOFIACALL declares the calling convention for exported functions */ #define SOFIACALL /* Win32 linkage */ /* Windows platform with MS/Borland/Cygwin/MinGW32 compiler */ #if defined(_WIN32) && \ (defined(_MSC_VER) || defined(__BORLANDC__) || \ defined(__CYGWIN__) || defined(__MINGW32__)) #undef SOFIACALL #define SOFIACALL __cdecl #if defined(LIBSOFIA_SIP_UA_STATIC) #else #undef SOFIAPUBFUN #undef SOFIAPUBVAR #if defined(IN_LIBSOFIA_SIP_UA)//在LIBSOFIA_SIP_UA工程内会事先定义这个宏 #define SOFIAPUBFUN __declspec(dllexport)//因为在LIBSOFIA_SIP_UA工程内所以是输出函数 #define SOFIAPUBVAR __declspec(dllexport) extern//因为在LIBSOFIA_SIP_UA工程内所以是输出函数 #else #define SOFIAPUBFUN __declspec(dllimport)//引入函数用 #define SOFIAPUBVAR __declspec(dllimport) extern//引入函数用 #endif #endif #if !defined _REENTRANT #define _REENTRANT #endif #elif defined (SYMBIAN) #undef SOFIACALL #define SOFIACALL __cdecl #if defined(LIBSOFIA_SIP_UA_STATIC) #else #undef SOFIAPUBFUN #undef SOFIAPUBVAR #if defined(IN_LIBSOFIA_SIP_UA) #define SOFIAPUBFUN __declspec(dllexport) #define SOFIAPUBVAR __declspec(dllexport) extern #else #define SOFIAPUBFUN __declspec(dllimport) #define SOFIAPUBVAR __declspec(dllimport) #endif #endif #if !defined _REENTRANT #define _REENTRANT #endif #endif
这里还考虑了SYMBIAN平台,因为不熟所以不考虑了解它们,只看Win32部分。因为这三个宏都必须重定义,所以在重定义前都先解除之前的宏定义。如果未定义宏_REENTRANT(可重入的意思),则errno当作一个全局变量处理。假如你的程序是多线程的,则应当定义_REENTRANT宏,那么errno将被扩展为一个函数,该函数将访问线程局部存储的错误码。。
su_config.h头文件最后部分内容如下。目的就是再为SOFIAPUBFUN生成一些别名。这些别名将在各个子模块内被使用。在子模块内这些使用,代码既显得一致规范又能少敲一些键盘。
#define BNF_DLL SOFIAPUBFUN #define HTTP_DLL SOFIAPUBFUN #define IPT_DLL SOFIAPUBFUN #define AUTH_DLL SOFIAPUBFUN #define MSG_DLL SOFIAPUBFUN #define NEA_DLL SOFIAPUBFUN #define NTA_DLL SOFIAPUBFUN #define NTH_DLL SOFIAPUBFUN #define SDP_DLL SOFIAPUBFUN #define SIP_DLL SOFIAPUBFUN #define SU_DLL SOFIAPUBFUN #define TPORT_DLL SOFIAPUBFUN #define URL_DLL SOFIAPUBFUN #define MSG_TEST_DLL SOFIAPUBFUN
此头文件中还剩GNUC编译器下__attrbute__的处理没看,暂放一旁。