阅读任何一个开源代码项目,最好阅读前了解作者开发这个软件前制定的一些约定。例如,命名规范,代码排版风格等。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__的处理没看,暂放一旁。