原创 翻译automake book9.1.3

2008-6-14 22:41 3772 8 8 分类: 工程师职场

<?xml:namespace prefix = st1 ns = "urn:schemas-microsoft-com:office:smarttags" />9.1.3 C++ Compilers <?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />


In order for a C++ program to use a library compiled with a C compiler, it is necessary for any symbols exported from the C library to be declared between `extern "C" {' and `}'. This code is important, because a C++ compiler mangles(7)使变形 all variable and function names, where as a C compiler does not. On the other hand, a C compiler will not understand these lines, so you must be careful to make them invisible to the C compiler.


Sometimes you will see this method used, written out in long hand in every installed header file, like this:


#ifdef __cplusplus


extern "C" {


#endif


...


#ifdef __cplusplus


}


#endif


But that is a lot of unnecessary typing if you have a few dozen headers in your project. Also the additional braces tend to confuse text editors, such as emacs, which do automatic source indentation缩进 based on brace characters.


Far better, then, to declare them as macros in a common header file, and use the macros in your headers:


  #ifdef __cplusplus


#  define BEGIN_C_DECLS extern "C" {


#  define END_C_DECLS   }


#else /* !__cplusplus */


#  define BEGIN_C_DECLS


#  define END_C_DECLS


#endif /* __cplusplus */


I have seen several projects that name such macros with a leading underscore下划线 -- `_BEGIN_C_DECLS'. Any symbol with a leading underscore is reserved for use by the compiler implementation, so you shouldn't name any symbols of your own in this way. By way of example, I recently ported the Small(8) language compiler to Unix, and almost all of the work was writing a Perl script to rename huge numbers of symbols in the compiler's reserved保留的 namespace to something more sensible so that GCC could even parse分析 the sources. Small was originally developed on Windows, and the author had used a lot of symbols with a leading underscore. Although his symbol names didn't clash冲突、抵触 with his own compiler, in some cases they were the same as symbols used by GCC.


9.1.4 Function Definitions


As a stylistic风格 convention惯例, the return types for all function definitions should be on a separate line. The main reason for this is that it makes it very easy to find the functions in source file, by looking for a single identifier at the start of a line followed by an open parenthesis:


$ egrep '^[_a-zA-Z][_a-zA-Z0-9]*[ \t]*\(' error.c


set_program_name (const char *path)


error (int exit_status, const char *mode, const char *message)


sic_warning (const char *message)


sic_error (const char *message)


sic_fatal (const char *message)


There are emacs lisp functions and various code analysis tools, such as ansi2knr (see section 9.1.6 K&R Compilers), which rely on this formatting convention, too. Even if you don't use those tools yourself, your fellow developers might like to, so it is a good convention to adopt.


9.1.1          C++编译器


为了在C++程序中使用C语言的函数库,C函数库中的符号必须在`extern "C" {'`}之间声明。因为C++编译器会把所有的变量和函数名进行重命名,而C编译器不会这样做,所以上述这些代码非常重要。另一方面,由于C编译器是无法理解这些语句的,所以当使用C编译器编译时必须使这些语句失效。


有时你可以看到该方法应用在所有的头文件中,如下所示:


#ifdef __cplusplus


extern "C" {


#endif


...


#ifdef __cplusplus


}


#endif


如果你在你的项目中只使用了少量的头文件,则完全没有必要键入上述这些代码。而且多余的大括号还会造成文本编辑器(比如emacs)的混乱,因为emacs是基于大括号来对代码进行自动缩进的。


更好的方法是在一个普通的头文件中把这些代码声明为宏,并且在你的头文件中使用它们:


#ifdef __cplusplus


#  define BEGIN_C_DECLS extern "C" {


#  define END_C_DECLS   }


#else /* !__cplusplus */


#  define BEGIN_C_DECLS


#  define END_C_DECLS


#endif /* __cplusplus */


我发现很多项目在给这些宏命名的时候使用下划线,比如_BEGIN_C_DECLS。所有以下划线开头的符号都是预留给编译器编译程序时使用的,所有你在给自己的符号命名时不可以用下划线开头。顺便举个例子,最近我移植一个Small语言编译器到Unix环境下,大部分的工作都是编写Perl教本来给大量预留给编译器命名空间使用的符号重命名。起初,Small是在Windows环境下开发的,并且作者使用很多以下划线开头的符号。虽然他的那些符合与他的编译器不冲突,但是在一些地方他使用的符号与GCC预留的符号相同。


9.1.2          函数定义


有一个习惯的风格就是在定义函数时函数的返回类型放在单独的一行。这个做法的主要原因就是在源文件中通过一个在一行的开始后面紧跟着“(”的标志符来快速找到相应的函数:


$ egrep '^[_a-zA-Z][_a-zA-Z0-9]*[ \t]*\(' error.c


set_program_name (const char *path)


error (int exit_status, const char *mode, const char *message)


sic_warning (const char *message)


sic_error (const char *message)


sic_fatal (const char *message)


有一些emacs lisp函数和很多代码分析工具,比如ansi2knr,也是依靠这些格式习惯起作用。即使你自己不会用这些工具,但是你的继任开发人员有可能会用到,所以这是一个值得采纳的好习惯。

文章评论0条评论)

登录后参与讨论
我要评论
0
8
关闭 站长推荐上一条 /2 下一条