? 經(jīng)常都會(huì)都會(huì)有讀者問如下類似的問題:
哪里有好的學(xué)習(xí)資源?
有值得學(xué)習(xí)和參考代碼嗎?
寫代碼怎么才能寫的漂亮?
? 其實(shí),我們身邊就有很多“好的資源”值得學(xué)習(xí),比如本文分享的?阿里 AliOS 的編碼風(fēng)格。 ?
分享正文之前推薦一個(gè)嵌入式招聘信息的平臺(tái):
1. 前言
本文是AliOS Things提供的一套C語言代碼規(guī)范,適用的對(duì)象為符合C99標(biāo)準(zhǔn)的C語言工程。
2. 命名
本節(jié)內(nèi)容均為建議,不作強(qiáng)制要求。
2.1. 總則
各種命名均使用英文單詞及其縮寫,非特殊情況不能使用漢語拼音或其他語言。
2.2. 文件命名
文件名全部使用小寫字母,用_連接。源文件使用.c后綴。頭文件使用.h后綴。
2.3. 類型命名
2.3.1. 簡(jiǎn)單類型命名
使用typedef自定義的簡(jiǎn)單類型命名全部使用小寫字母,用_連接,以_t結(jié)尾。例如:
?
?
typedef?int32_t?aos_status_t;
2.3.2. 結(jié)構(gòu)體和聯(lián)合體命名
結(jié)構(gòu)體和聯(lián)合體類型命名全部使用小寫字母,用_連接。建議使用typedef定義一個(gè)整體的名字,以_t結(jié)尾。例如:
?
?
typedef?struct?aos_list_node?{ ????struct?aos_list_node?*prev; ????struct?aos_list_node?*next; }?aos_list_node_t; static?aos_list_node_t?list_node;
2.3.3. 枚舉命名
枚舉類型命名全部使用小寫字母,用_連接。建議使用typedef定義一個(gè)整體的名字,以_t結(jié)尾。枚舉值命名全部使用大寫字母,用_連接,包含表示類型的前綴。例如:
?
?
typedef?enum?aos_socket_stage?{ ????AOS_SOCK_STG_DISCONNECTED, ????AOS_SOCK_STG_CONNECTED, }?aos_socket_stage_t; static?aos_socket_stage_t?sock_stage?=?AOS_SOCK_STG_DISCONNECTED;
2.4. 變量命名
變量命名全部使用小寫字母,用_連接。數(shù)組名稱盡量使用復(fù)數(shù)名詞。例如:
?
?
cfg_file_t?cfg_files[NUM_CFG_FILES];
表示數(shù)目的變量名稱使用num(number的縮寫)加復(fù)數(shù)名詞。例如:
?
?
unsigned?int?num_files;
表示序號(hào)的變量名稱使用單數(shù)名詞加num或index或idx(index的縮寫)。例如:
?
?
unsigned?int?file_num; unsigned?int?file_index;
2.5. 函數(shù)命名
函數(shù)命名全部使用小寫字母,用_連接。
2.6. 宏命名
一般的宏命名全部使用大寫字母,用_連接。例如:
?
?
#define?AOS_STRING_MAX_LEN?127
模擬函數(shù)使用方式的宏的命名規(guī)則與函數(shù)相同。例如:
?
?
#define?aos_dev_set_id(dev,?x)? ????do?{? ????????(dev)->id?=?(x);? ????}?while?(0)
2.7. 前綴
為防止命名空間污染,公用組件中的非static函數(shù)、非static全局變量、全局類型、全局宏的命名應(yīng)帶有前綴。例如(假設(shè)前綴為aos):
?
?
void?aos_cfg_file_close(int?fd); extern?char?**aos_process_argv; typedef?struct?aos_list_node?aos_list_node_t; #define?AOS_STRING_MAX_LEN?127
3. 格式
3.1. 文本格式
源文件、頭文件、Makefile等文本文件一律采用UTF-8 without BOM編碼,采用Unix風(fēng)格換行格式。文本文件末尾應(yīng)有且只有一個(gè)換行符,即末尾應(yīng)有且只有一個(gè)空行。
3.2. 行長(zhǎng)度
每行字符數(shù)原則上不超過120。包含長(zhǎng)路徑的#include語句、頭文件#define保護(hù)可以無視此規(guī)則。
3.2.1. 表達(dá)式換行
較長(zhǎng)的表達(dá)式可在運(yùn)算符處換行,換行處的運(yùn)算符屬于舊行,新行對(duì)齊到舊行中的相同邏輯層級(jí)。例如:
?
?
void?foo(void) { ????if?((aos_list_next(list_node)?!=?&list_head?&&?!priv)?|| ????????!(strcmp(symbol,?default_symbol)?&&?blahblahblahblahblahblah()?&& ??????????meomeomeomeomeomeomeomeomeomeomeomeomeomeomeomeo(NULL)))?{ ????????/*?...?*/ ????} }
3.2.2. 函數(shù)換行
較長(zhǎng)的函數(shù)定義、聲明可在返回值類型和函數(shù)名稱之間換行。若返回值為指針類型,*屬于新行。例如:
?
?
static?unsigned?long blahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblah(void); static?const?manager_priv_t *blahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblah(int?index);
較長(zhǎng)的函數(shù)定義、聲明、調(diào)用可在參數(shù)列表中間換行,參數(shù)列表中間換行后新行應(yīng)縮進(jìn)至舊行第一個(gè)參數(shù)處。例如:
?
?
void?blahblahblahblahblahblahblahblahblah(manager_priv_t?*priv,?int?index, ??????????????????????????????????????????const?char?*proc_name); void?foo(void) { ????blahblahblahblahblahblahblahblahblahblah(get_manager_priv(manager),?0, ?????????????????????????????????????????????"meomeomeomeomeomeomeomeo"); }
3.2.3. 字符串換行
較長(zhǎng)的字符串可在空格處換行,一般情況下?lián)Q行處的空格屬于舊行。例如:
?
?
void?foo(void) { ????printf("The?GNU?operating?system?consists?of?GNU?packages?" ???????????"(programs?specifically?released?by?the?GNU?Project)?" ???????????"as?well?as?free?software?released?by?third?parties. "); }
3.3. 縮進(jìn)
使用空格縮進(jìn),每次4個(gè)空格。全文不應(yīng)出現(xiàn)制表符(tab)。例如:
?
?
void?foo(unsigned?int?nbr_processes) { ????unsigned?int?i; ????while?(i?
宏定義、行尾注釋、結(jié)構(gòu)體、聯(lián)合體、枚舉等內(nèi)部可縮進(jìn)實(shí)現(xiàn)多行對(duì)齊,但不作強(qiáng)制要求。若有縮進(jìn),應(yīng)對(duì)齊到4的整數(shù)倍。例如:
?
?
/*?此處數(shù)字0縮進(jìn)32個(gè)字符,即位于第33列。?*/ #define?STAGE_UPDATE_CONTINUE???0 #define?STAGE_UPDATE_COMPLETE???1 /*?合法?*/ #define?EVENT_RX_FULL?(1U?<0) #define?EVENT_TX_EMPTY?(1U?<1) typdef?enum?socket_stage?{ ????/*?此處等號(hào)縮進(jìn)32個(gè)字符,即位于第33列。?*/ ????SOCK_STG_DISCONNECTED???????=?0, ????SOCK_STG_CONNECTED??????????=?1, }?socket_stage_t; /*?此處反斜杠縮進(jìn)40個(gè)字符,即位于第41列。?*/ #define?aos_dev_set_flags(dev,?x)??????? ????do?{???????????????????????????????? ????????(dev)->flags?=?(x);????????????? ????}?while?(0) /*?合法?*/ #define?aos_dev_set_ops(dev,?x)? ????do?{? ????????(dev)->ops?=?(x);? ????}?while?(0) /*?此處注釋縮進(jìn)24個(gè)字符,即位于第25列。?*/ foo(NULL);??????????????/*?abc?*/ blahblahblahblahblah();?/*?xyz?*/ /*?合法?*/ foofoofoo();?/*?abc?*/ foofoo();?/*?xyz?*/
分行定義的宏,第二行起應(yīng)縮進(jìn)一次。例如:
?
?
#define?aos_dev_set_id(dev,?x)? ????do?{? ????????(dev)->id?=?(x);? ????}?while?(0)
switch塊中的case語句和default語句與switch語句縮進(jìn)層級(jí)相同。例如:
?
?
switch?(stage)?{ case?SOCK_STG_DISCONNECTED: ????foo(); ????break; case?SOCK_STG_CONNECTED: ????sock->connected?=?1; ????break; default: ????break; }
3.4. 花括號(hào)
函數(shù)體的左花括號(hào)另起一行;其他情況下左花括號(hào)不另起一行。一般情況下左花括號(hào)后續(xù)內(nèi)容另起一行;宏定義中、數(shù)組、結(jié)構(gòu)體、聯(lián)合體初始化時(shí)若花括號(hào)中內(nèi)容較短則左花括號(hào)后續(xù)內(nèi)容可以不另起一行。一般情況下右花括號(hào)另起一行;宏定義中、數(shù)組、結(jié)構(gòu)體、聯(lián)合體初始化時(shí)若花括號(hào)中內(nèi)容較短則右花括號(hào)可以不另起一行。右花括號(hào)與后續(xù)內(nèi)容組合成一行。例如:
?
?
typedef?struct?manager_priv?{ ????int?index; ????void?*data; }?manager_priv_t; #define?set_manager_index(x,?idx)?do?{?(x)->priv->index?=?(idx);?}?while?(0) #ifdef?__cplusplus extern?"C"?{ #endif void?foo(void) { ????int?i?=?0; ????/*?...?*/ ????if?(i?==?0)?{ ????????/*?...?*/ ????}?else?{ ????????/*?...?*/ ????} } manager_priv_t?priv?=?{?0,?NULL,?}; #ifdef?__cplusplus } #endif
3.5. 空格
行尾不應(yīng)有空格。三元操作符和二元操作符(獲取成員的.和->操作符除外)前后留有空格。例如:
?
?
x?=?a???b?:?c; v?=?w?*?x?+?y?/?z; len?=?x.length; priv?=?proc->priv;
一元操作符與參數(shù)之間不留空格。例如:
?
?
x?=?*p; p?=?&x; i++; j?=?--i;
逗號(hào)右側(cè)若有內(nèi)容,逗號(hào)與右側(cè)內(nèi)容之間應(yīng)有空格。例如:
?
?
void?foo(int?x,?int?y);
分號(hào)右側(cè)若有內(nèi)容(右圓括號(hào)或另外一個(gè)分號(hào)除外),分號(hào)與右側(cè)內(nèi)容之間應(yīng)有空格。例如:
?
?
for?(i?=?0;?i?
圓括號(hào)內(nèi)部?jī)?nèi)容與圓括號(hào)之間不留空格。例如:
?
?
len?=?strlen(name); for?(i?=?0;?i?
圓括號(hào)與左側(cè)關(guān)鍵字之間應(yīng)有空格。例如:
?
?
while?(1)?{ ????/*?...?*/ } if?(i?==?0)?{ ????/*?...?*/ }
圓括號(hào)與左側(cè)函數(shù)名之間不留空格。例如:
?
?
int?load_file(const?char?*name) { ????foo(0); ????/*?...?*/ }
類型轉(zhuǎn)換中的圓括號(hào)與右側(cè)內(nèi)容之間不留空格。例如:
?
?
manager_priv_t?*priv?=?(manager_priv_t?*)p;
方括號(hào)與左側(cè)內(nèi)容、內(nèi)部?jī)?nèi)容之間不留空格。例如:
?
?
c?=?name[i];
左花括號(hào)左側(cè)或右側(cè)若有內(nèi)容,左右內(nèi)容與左花括號(hào)之間應(yīng)有空格。右花括號(hào)左側(cè)若有內(nèi)容,左側(cè)內(nèi)容與右花括號(hào)之間應(yīng)有空格;右花括號(hào)右側(cè)若有內(nèi)容(分號(hào)、逗號(hào)除外),右側(cè)內(nèi)容與右花括號(hào)之間應(yīng)有空格。例如:
?
?
#define?set_manager_index(x,?idx)?do?{?(x)->priv->index?=?(idx);?}?while?(0) manager_priv_t?priv?=?{?0,?NULL,?};
分行定義的宏,與左側(cè)內(nèi)容之間應(yīng)有空格。例如:
?
?
#define?set_manager_index(x,?idx)? ????do?{? ????????(x)->priv->index?=?(idx);? ????}?while?(0)
3.6. 指針
指針聲明或定義時(shí),*應(yīng)靠近變量名稱。*與修飾符之間應(yīng)有空格。例如:
?
?
int?*p; const?char?*name; void?*?const?ptr; void?(*func)(void?*arg);
3.7. 數(shù)值常量
十六進(jìn)制數(shù)字A?~?F使用大寫形式。表示二進(jìn)制的前綴0b和表示十六進(jìn)制的0x使用小寫形式。后綴U和L使用大寫形式。后綴f使用小寫形式。表示冪的e和p使用小寫形式。例如:
?
?
unsigned?int?b?=?0b0101; unsigned?int?x?=?0xABCDEF; unsigned?int?u?=?0U; long?int?l?=?0L; unsigned?long?int?ul?=?0UL; float?f?=?1.0f; long?double?ld?=?1.0L; double?dd?=?-1.5e-5; double?xd?=?0xA.Bp12;
3.8. 注釋
使用C90風(fēng)格的/* */,不使用C++風(fēng)格的//。?/*或*/與注釋正文之間應(yīng)有空格。行尾的注釋和代碼之間應(yīng)有空格。完整語句注意首字母大寫和標(biāo)點(diǎn)符號(hào),簡(jiǎn)單詞組可以不使用標(biāo)點(diǎn)。注意區(qū)分中英文標(biāo)點(diǎn)。?TODO:使用特定注釋格式可利用doxygen等自動(dòng)化工具生成文檔。例如:
?
?
/* ?*?This?source?file?is?part?of?AliOS?Things. ?*?Zhang?San?
4. 頭文件
4.1. 路徑
為避免與第三方庫的頭文件命名沖突,公用組件的頭文件應(yīng)存放于子目錄中,引用時(shí)路徑包含子目錄名稱。例如:
?
?
#include?
4.2. 引號(hào)和尖括號(hào)
只有包含與本源文件處于同路徑中的頭文件時(shí)使用引號(hào),其他情況均使用尖括號(hào)。例如:
?
?
#include?
4.3. 包含次序
包含頭文件的次序如下:|次序 |種類| |-:- |:-| |1 |C語言標(biāo)準(zhǔn)庫頭文件和工具鏈頭文件| |2 |公用組件的頭文件| |3 |本工程頭文件|
例如:
?
?
#include?
4.4. 保護(hù)
所有頭文件都應(yīng)該使用#define保護(hù)來防止被重復(fù)包含。相關(guān)宏命名格式是PATH_FILE_H。例如,頭文件aos/common.h可按如下方法保護(hù):
?
?
#ifndef?AOS_COMMON_H #define?AOS_COMMON_H /*?全部?jī)?nèi)容?*/ #endif?/*?AOS_COMMON_H?*/
4.5. 函數(shù)、變量聲明
頭文件中的函數(shù)聲明不使用extern關(guān)鍵字。頭文件中的全局變量聲明使用extern關(guān)鍵字。例如:
?
?
void?aos_cfg_file_close(int?fd); extern?char?**aos_process_argv;
4.6. extern "C"關(guān)鍵字
公用頭文件中聲明的函數(shù)和全局變量應(yīng)該使用extern "C"關(guān)鍵字修飾。?#include不應(yīng)使用extern "C"關(guān)鍵字修飾。?#define、類型定義不作要求,可酌情考慮。例如:
?
?
#ifndef?AOS_COMMON_H #define?AOS_COMMON_H #include?
5. 其他注意事項(xiàng)
只在本編譯單元使用的函數(shù)、全局變量應(yīng)使用static修飾符。在不影響功能的前提下,指針類型的函數(shù)參數(shù)盡量使用const修飾符。自增、自減運(yùn)算符單獨(dú)使用時(shí)采用后置形式。數(shù)組、結(jié)構(gòu)體初始化列表、枚舉類型定義中的最后一個(gè)成員之后應(yīng)有逗號(hào)。例如:
?
?
int?offsets[]?=?{ ????0, ????1, };
審核編輯:湯梓紅
評(píng)論