/* Interface from Emacs to terminfo.
Copyright (C) 1985, 1986 Free Software Foundation, Inc.
This file is part of GNU Emacs.
GNU Emacs is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
GNU Emacs is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU Emacs; see the file COPYING. If not, write to
the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
#include
#include "lisp.h"
/* Define these variables that serve as global parameters to termcap,
so that we do not need to conditionalize the places in Emacs
that set them. */
char *UP, *BC, PC;
/* Interface to curses/terminfo library.
Turns out that all of the terminfo-level routines look
like their termcap counterparts except for tparm, which replaces
tgoto. Not only is the calling sequence different, but the string
format is different too.
*/
char *
tparam (string, outstring, len, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9)
char *string;
char *outstring;
int arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9;
{
char *temp;
extern char *tparm();
temp = tparm (string, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9);
if (outstring == 0)
outstring = ((char *) (xmalloc ((strlen (temp)) + 1)));
strcpy (outstring, temp);
return outstring;
}
分析上面的代码可以看出GNU的编码风格如下所示。
● 函数开头的左花括号放到最左边,避免把任何其他的左花括号、左括号或者左方括号放到最左边。
● 尽力避免让两个不同优先级的操作符出现在相同的对齐方式中。
● 每个程序开头都应该有一段简短地说明其功能的注释。例如GNU emacs上面的代码中的注释如下所示。
/* Define these variables that serve as global parameters to termcap,
so that we do not need to conditionalize the places in Emacs
that set them. */
● 每个函数都书写注释,以说明函数做了些什么,需要哪些种类的参数,参数可能值的含义以及用途。
● 不要跨行声明多个变量。在每一行中都以一个新的声明开头。
● 当在一个if语句中嵌套了另一个if-else语句时,应用花括号把if-else括起来。
● 要在同一个声明中同时说明结构标识和变量,或者结构标识和类型定义(typedef)。
● 尽量避免在if的条件中进行赋值。
● 在名字中使用下划线以分隔单词,尽量使用小写;在宏或者枚举中通常使用大写常量。
● 使用一个命令行选项时,给出的变量应该在选项含义的说明之后,而不是选项字符之后。
看了上面两种风格的介绍,读者是不是觉得有些太多了,难以记住?不要紧,Linux有很多工具来帮助我们。除了vim和emacs以外,还有一个非常有意思的小工具 indent可以帮我们美化C/C++源代码。
下面用这条命令将Linux 内核编程风格的程序quan.c转变为GNU编程风格。
[david@localhost ~]$ indent -gnu quan.c
利用indent这个工具,大家就可以方便地写出漂亮的代码来。
更为详细的GNU的编码风格,读者可以在
http://www.gnu.org/prep/standards/standards.html阅读Richard Stallman所写的《GNU Coding Standards》一文。
下面是 Linux 内核2.6.13中的\arch\i386\kernel中的numaq.c的节选代码,现在并不要求读懂此代码,而是看Linux的内核编程风格。
/*
* Written by: Patricia Gaughen, IBM Corporation
*
* Copyright (C) 2002, IBM Corp.
*
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
* NON INFRINGEMENT. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* Send feedback to <gone@us.ibm.com>
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define MB_TO_PAGES(addr) ((addr) << (20 - PAGE_SHIFT))
/*
* Function: smp_dump_qct()
*
* Description: gets memory layout from the quad config table. This
* function also updates node_online_map with the nodes (quads) present.
*/
static void __init smp_dump_qct(void)
{
int node;
struct eachquadmem *eq;
struct sys_cfg_data *scd =
(struct sys_cfg_data *)__va(SYS_CFG_DATA_PRIV_ADDR);
nodes_clear(node_online_map);
for_each_node(node) {
if (scd->quads_present31_0 & (1 << node)) {
node_set_online(node);
eq = &scd->eq[node];
/* Convert to pages */
node_start_pfn[node] = MB_TO_PAGES(
eq->hi_shrd_mem_start - eq->priv_mem_size);
node_end_pfn[node] = MB_TO_PAGES(
eq->hi_shrd_mem_start + eq->hi_shrd_mem_size);
memory_present(node,
node_start_pfn[node], node_end_pfn[node]);
node_remap_size[node] = node_memmap_size_bytes(node,
node_start_pfn[node],
node_end_pfn[node]);
}
}
}
分析以上代码可以得出Linux内核代码的风格如下:
● 缩进采用的是tab制表符。
● 在if或者for循环中,将开始的大括号放在一行的最后,而将结束大括号放在本段语句结束行的第一位,但是函数中的大括号除外。
● 命名系统。变量命名尽量使用简短的名字,简写或者单词间采用了_ 隔开,比如代码中的sys_cfg_data。
● 函数最好要短小精悍,一个函数最好只做一件事情,而且函数中的变量一般都不超过10个,大小一般都小于80行。
● 注释。一个模块的注意一般注明了作者、版权、注释说明代码的功能,而不是说明其实现原理,这也和Linux的文化有关,Linus Torvald在回答有人问题时,经常说的第一句话说的第一句话是"阅读源代码(RTFSC)"(Read the fucking source code)
看了上面两种风格的介绍,读者是不是觉得有些太多了,难以记住?不要紧,Linux有很多工具来帮助我们。除了vim和emacs以外,还有一个非常有意思的小工具 indent可以帮我们美化C/C++源代码。
下面用这条命令将Linux 内核编程风格的程序quan.c转变为 GNU编程风格,代码如下:
[david@localhost ~]$ indent -gnu quan.c
利用indent这个工具,大家就可以方便地写出漂亮的代码来。
以上分别学习了GNU编码风格和Linux内核编码风格,两种风格之间体现着两种不同的文化精神,有些地方相似,有些地方迥然不同,但是目的只有一个形成一个清晰、美观、可维护、方便扩展的代码。而在实际项目开发中作者提出以下建议。
● 关于主函数。主函数如果不考虑命令行参数的话,可以写成
int main(void)
如果有命令参数的话可以写成
int main( int argc, char **argv )
● 关于缩进。可以采用空格或者tab制表符,但是在同一代码中不要混合使用tab指标符号,或者空格,因为大家可能使用不同的编辑器,有些编辑器认为一个tab制表符相当于8个空格,而有些编辑器认为是3个空格,容易造成代码结构的混乱。
● 关于命名规则。在通常情况下,具有前缀和后缀的下划线的名称是为系统用途而保留的,如_sys_等,不应当用于任何用户创建的名称。变量名称的命名规则可以参考Linux内核命名规则,简介但是有效。但还要注意以下宿订约成:
à #define 常量应全部大写。
à num 常量应以大写字母开头或全部大写。
à 函数、类型定义(typedef)和变量名以及结构(struct)、联合(union)和枚举(enum)标记名称应小写。
关于指针。声明指针的限定符号应该在变量前面,而不是类型后面,如下代码
char *david,*xueer;
而不应该是下面这样
char* david,xueer;
关于注释。注释的益处对于读者来说不言自明。不能过量的使用注释,在没一行都用注释,不但增加了工作量,还会使得代码比较乱。综合GNU编码风格和Linux内核编码风格,在实际项目中可以采用以下编码风格:每个模块要注明作者、版本历史、最后修改时间、实现的功能以及接口,对每个函数说明其原理‘在关键算法部分进行说明’或者在作者认为比较晦涩的代码部分也要作相关的注释。缩进采用的是tab制表符。