Linux C语言的编程规范
(Linux)有独特的(编程)风格,在内核源代码目录Documentation/CodingStyle,详细描述代码风格。
建议大家可以去看一下,老外写技术文档还是很有意思的,上来就狂喷,“你不这样写就会完蛋,异教徒才不这样写……”,没有国内那么刻板,多阅读英语文档对技术增长很有帮助。
1. 命名规范
在一般编程中,习惯以如下方式命名宏、变量和函数:
#define (PI) 3.1415926 /*用大写字母代表宏 */int minValue, maxValue; /*变量:第一个单词全小写,其后单词的第一个字母大写*/void SendData (void); /* 函数:所有单词第一个字母都大写 */ 这种通过单词之间通过首字母大写来区分的方式非常流行。通过第1个单词的首字母是否大写可以区分名称属于变量还是属于函数,而看到整串的大写字母可以断定为宏。
许多领域的程序开发都遵照此习惯。
但是Linux不以这种习惯命名,对于上面的一段程序,在Linux中它会被命名为:
#define PI 3.1415926int min_value, max_value;void send_data (void); 在上述命名方式中,宏还是一样用大写,但变量和函数名,不按照Windows所采用的用首字母大写来区分单词,而是采用下划线。而且Linux下命名,全局变量命名最好用长的准确的描述,局部变量最好简短,甚至直接用tmp,i之类的。
其实两种命名方式都行,写Liunx下的程序时,与Linux社区代码风格一致更好,但你用第一种我觉得也无伤大雅。
2.缩进
缩进统一使用"TAB",而不是空格括号。
另外提一句:在Linux下,"TAB"代表8个字符,而不是4个,Linux代码风格认为8个字符更能体现层次结构。文档里喷"TAB"为4字符的是异教徒,对于8字符在多层次时,代码太偏右的问题,文档又喷层次超过三层,你的代码就会完蛋,哈哈哈。
为了减少层次,在switch/case语句方面, Linux 建议switch和case对齐,例如:
switch (suffix) {case 'G':case 'g': mem 3. Linux中代码括号“{”和“}”的使用原则
1)对于结构体、if/f(or)/while/switch语句, “{”不另起一行,例如:
struct var_data { int len; char data[0];};if (a == b) { a = c; d = a;}for (i = 0; i 2)如果if、for循环后只有1行,不要加“{”和“}”,例如:
for (i = 0; i 应该改为:
for (i = 0; i if和else混用的情况下, else语句不另起一行,例如: if (x == y){ ...} else if (x > y) { ...} else { ...} 4)对于函数, “{”另起一行,例如:
int (ad)d (int a, int b)[ return a + b;} 4. 空格的使用
1)关键字后加空格
在这些关键字后面加空格:
if, switch, case, for, do, while
但是这些不加:
sizeof, typeof, alignof, attribu(te)
例如:
s = sizeof(struct file); 2)括号内,紧挨着括号不加空格
错误示范:
s = sizeof( struct file ); 3)对于指针,”*“号挨着名字而不是类型
例如:
char *linux_banner;unsigned long long mempa(rs)e(char *ptr, char **retptr);char *match_strdup((sub)string_t *s); 4)操作符两侧加空格
以下二元或三元操作符两侧要加空格:
= + - * / % | " class="hljs typescript vditor-linenumber">int system_is_up(void){ return system_state == SYSTEM_RUNNING;}EXPORT_SYMBOL(system_is_up); 6. goto语句的使用
用不用goto一直是一个著名的争议(话题), Linux内核源代码中对goto的应用非常广泛,但是一般只限于错误处理中,其结构如:
if(register_a() != 0) goto err;if (register_b() != 0) goto errl;if(register_c() != 0) goto err2;if (register_d () != 0) goto err3;err3: unregister_c();err2: unregister_b ();errl: unregister_a ();err: return ret; 这种将goto用于错误处理的用法实在是简单而高效,只需保证在错误处理时注销、资源释放等,与正常的注册、资源申请顺序相反。
printf输出格式linux 7. 解释
Linux风格的解释是c89 "/… /”风格。不要使用c99风格的“//…”解释。
长(多行)解释的首选样式是:
/* * This is the preferred style for multi-line * comments in the Linux kernel source code. * Please use it consistently. * * Description: A column of asterisks on the left side, * with beginning and ending almost-blank lines. */ 8.do {} while(0) 语句
在Linux内核中,经常会看到do {} while(0)这样的语句。
许多人开始都会疑惑,认为do while(0)毫无意义,因为它只会执行一次,加不加do {} while(0)效果是完全一样的,其实do {} while(0)的用法主要用于宏定义中。
这里用一个简单的宏来演示:
#define SAFE_FREE (p) do{ free (p); p = NULL;} while (0) 假设这里去掉do...while(0),即定义SAFE_DELETE为:
#define SAFE FREE (p) free (p); p = NULL; 那么以下代码:
if (NULL != p) SAFE_DELETE(p)else .../* do something */ 会被展开为:
if (NULL != P) free (p); p = NULL;else .../* do something */ 展开的代码中存
在两个问题:
1)因为if分支后有两个语句,导致else分支没有对应的if,编译失败。
2)假设没有else分支,则SAFE_FREE中的第二个语句无论if测试是否通过,都会执行。
的确,将SAFE_FREE的定义加上{}就可以解决上述问题了,即:
#define SAFE_FREE (p) { free (p); p= NULL; } 这样,代码:
if (NULL != p) SAFE_DELETE(p)else ... /* do something */ 会被展开为:
if (NULL != p) { free (p); P = NULL; }else .../* do something */ 但是,在C程序中,在每个语句后面加分号是一种约定俗成的习惯,那么,如下代码:
if (NULL != p) SAFE_DELETE (p);else .... /* do something */ 将被扩展为:
if (NULL != p) { free (p); p = NULL; };else .../* do something */ 这样else分支就又没有对应的if了,编译将无法通过。
假设用了do {} while(0)语句,情况就不一样了,同样的代码会被展开为:
if (NULL != p) do{ free (p); p= NULL; } while (0);else .../* do something */ 而不会再出现编译问题。do{} while(0)的使用完全是为了保证宏定义的使用者能无编译错误地使用宏,它不对其使用者做任何假设。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论