GNOME C规范

以下内容来自GNOME的开发文档,https://developer.gnome.org/documentation/guidelines/programming/coding-style.html

缩进

Linux 内核风格是一个tab缩进8个字符,GNU风格是一个tab 2个字符,这两种都可以,但要统一。

括号

if else,如果只有一条语句,可以不写大括号,如下:

1
2
3
4
5
/* valid */
if (condition)
single_statement ();
else
another_single_statement (arg1);

但也有例外。

第一种,if语句有大括号,else语句也要有大括号。

1
2
3
4
5
6
7
8
9
10
/* valid */
if (condition)
{
foo ();
bar ();
}
else
{
baz ();
}

第二种,单个语句写了多行,也要用大括号。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/* valid Linux kernel style */
if (condition) {
a_single_statement_with_many_arguments (some_lengthy_argument,
another_lengthy_argument,
and_another_one,
plus_one);
} else
another_single_statement (arg1, arg2);

/* valid GNU style */
if (condition)
{
a_single_statement_with_many_arguments (some_lengthy_argument,
another_lengthy_argument,
and_another_one,
plus_one);
}
else
{
another_single_statement (arg1, arg2);
}

第三种,如果if的条件有多行,也需要用大括号。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/* valid Linux kernel style */
if (condition1 ||
(condition2 && condition3) ||
condition4 ||
(condition5 && (condition6 || condition7))) {
a_single_statement ();
}

/* valid GNU style */
if (condition1 ||
(condition2 && condition3) ||
condition4 ||
(condition5 && (condition6 || condition7)))
{
a_single_statement ();
}

第四种情况,if嵌套,这时也需要用大括号。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/* valid Linux kernel style */
if (condition) {
if (another_condition)
single_statement ();
else
another_single_statement ();
}

/* valid GNU style */
if (condition)
{
if (another_condition)
single_statement ();
else
another_single_statement ();
}

函数

函数返回值类型独占一行

1
2
3
4
5
void
my_function (void)
{
// ...
}

函数参数一行一个,参数名称左对齐

1
2
3
4
5
6
7
8
void
my_function (some_type_t type,
another_type_t *a_pointer,
double_ptr_t **double_pointer,
final_type_t another_type)
{
// ...
}

空格

在括号前加空格,不要在括号后加空格

1
2
3
4
5
if (condition)
do_my_things ();

switch (condition) {
}

定义结构体时,使用空行,将不同类型的数据隔开

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
struct _GtkWrapBoxPrivate
{
GtkOrientation orientation;
GtkWrapAllocationMode mode;

GtkWrapBoxSpreading horizontal_spreading;
GtkWrapBoxSpreading vertical_spreading;

guint16 spacing[2];

guint16 minimum_line_children;
guint16 natural_line_children;

GList *children;
};

不要随便删除空行或空格,下面是错误的示范

1
2
/* invalid */
if (condition) foo (); else bar ();

switch

每个case的缩进级别应该相同,而且case的缩进应该与switch的大括号级别一致,一个case结束后,加一个空行,再开始下一个case。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/* valid Linux kernel style */
switch (condition) {
case FOO:
do_foo ();
break;

case BAR:
do_bar ();
break;
}

/* valid GNU style */
switch (condition)
{
case FOO:
do_foo ();
break;

case BAR:
do_bar ();
break;

default:
do_default ();
}

头文件

头文件中函数定义要用三列。

1
2
3
return_type          function_name           (type   argument,
type argument,
type argument);

每列最大的宽度要以每列中最大的宽度为准。

1
2
3
4
void        gtk_type_set_property (GtkType     *type,
const char *value,
GError **error);
const char *gtk_type_get_property (GtkType *type);

如果要定义一个公共库,把小的头文件包括到单一的一个公共库头文件中,而不是在应用中导入多个小的头文件。比如,GTK库定义了一些头文件,但是能直接调用的,就是gtk.h,其他的库不能在应用中直接调用。

1
2
3
4
5
6
// The __GTK_H_INSIDE__ symbol is defined in the gtk.h header
// The GTK_COMPILATION symbol is defined only when compiling
// GTK itself
#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
#error "Only <gtk/gtk.h> can be included directly."
#endif

对于库,所有的头文件都要有inclusion guards。下面这串代码演示了如何使用#ifndef和#endif来避免头文件被重复引用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#pragma once
//Time Class definition
//member functions are declared in time.cpp

//prevent multiple inclusions of header
#ifndef TIME_H
#define TIME_H

//time class definition
class time
{
public:
Time();//constructor
void setTime(int, int, int);//set hour, minute and second
void printUniversal() const;//print time in universal-time format
void printStandard() const;//print time in standard-time format

private:
unsigned int hour;//0-23
unsigned int minute;//0-59
unsigned int second;//0-59

};

#endif // !TIME_H

GObject 类

类型声明应该放在文件最开始的位置

1
2
typedef struct _GtkBoxedStruct       GtkBoxedStruct;
typedef struct _GtkMoreBoxedStruct GtkMoreBoxedStruct;

下面的没看懂什么意思……

内存申请

在堆栈中动态申请内存,用g_new(), 公共的结构类型要填充0,或是使用g_new0()来申请内存。

宏Macros

尽量避免用私有宏,返回的时候,记得#undef它们,最好是使用inline函数。公共宏除非是返回一个常值,否则不要使用。