最重要的一條規(guī)則
編寫代碼時最重要的一條規(guī)則是:檢查周圍的代碼并嘗試模仿它。
作為維護人員,如果收到的補丁明顯與周圍代碼的編碼風格不同,這是令人沮喪的。這是不尊重人的,就像某人穿著泥濘的鞋子走進一間一塵不染的房子。
因此,無論本文推薦的是什么,如果已經(jīng)編寫了代碼并且您正在對其進行修補,請保持其當前的樣式一致,即使它不是您最喜歡的樣式。
一般規(guī)則
這里列出了最明顯和最重要的一般規(guī)則。在你繼續(xù)閱讀其他章節(jié)之前,請仔細檢查它們。
使用C99標準
不使用制表符,而是使用空格
每個縮進級別使用4個空格
在關鍵字和左括號之間使用一個空格
在函數(shù)名和左括號之間不要使用空格
?
int32_t?a?=?sum(4,?3);??????????????/*?OK?*/ int32_t?a?=?sum?(4,?3);?????????????/*?Wrong?*/
?
不要在變量/函數(shù)/宏/類型中使用__或_前綴。這是為C語言本身保留的
對于嚴格的模塊私有函數(shù),使用prv_ name前綴
對于包含下劃線_ char的變量/函數(shù)/宏/類型,只能使用小寫字母
左花括號總是與關鍵字(for, while, do, switch, if,…)在同一行
?
size_t?i; for?(i?=?0;?i?5;?++i)?{???????????/*?OK?*/ } for?(i?=?0;?i?5;?++i){????????????/*?Wrong?*/ } for?(i?=?0;?i?5;?++i)?????????????/*?Wrong?*/ { }
?
在比較操作符和賦值操作符之前和之后使用單個空格
?
int32_t?a; a?=?3?+?4;??????????????/*?OK?*/ for?(a?=?0;?a?5;?++a)?/*?OK?*/ a=3+4;??????????????????/*?Wrong?*/ a?=?3+4;????????????????/*?Wrong?*/ for?(a=0;a<5;++a)???????/*?Wrong?*/
?
每個逗號后用單空格
?
func_name(5,?4);????????/*?OK?*/ func_name(4,3);?????????/*?Wrong?*/
?
不要初始化靜態(tài)和全局變量為0(或NULL),讓編譯器為您做
?
static?int32_t?a;???????/*?OK?*/ static?int32_t?b?=?4;???/*?OK?*/ static?int32_t?a?=?0;???/*?Wrong?*/ void my_func(void)?{ ????static?int32_t*?ptr;/*?OK?*/ ????static?char?abc?=?0;/*?Wrong?*/ }
?
在同一行中聲明所有相同類型的局部變量
?
void my_func(void)?{ ????char?a;?????????????/*?OK?*/ ????char?b;?????????????/*?Wrong,?variable?with?char?type?already?exists?*/ ????char?a,?b;??????????/*?OK?*/ }
?
按順序聲明局部變量
i.自定義結構和枚舉
ii.整數(shù)類型,更寬的無符號類型優(yōu)先
iii.單/雙浮點
?
int my_func(void)?{ ????/*?1?*/ ????my_struct_t?my;?????/*?First?custom?structures?*/ ????my_struct_ptr_t*?p;?/*?Pointers?too?*/ ????/*?2?*/ ????uint32_t?a; ????int32_t?b; ????uint16_t?c; ????int16_t?g; ????char?h; ????/*?...?*/ ????/*?3?*/ ????double?d; ????float?f; }
?
總是在塊的開頭聲明局部變量,在第一個可執(zhí)行語句之前
在for循環(huán)中聲明計數(shù)器變量
?
/*?OK?*/ for?(size_t?i?=?0;?i?10;?++i) /*?OK,?if?you?need?counter?variable?later?*/ size_t?i; for?(i?=?0;?i?10;?++i)?{ ????if?(...)?{ ????????break; ????} } if?(i?==?10)?{ } /*?Wrong?*/ size_t?i; for?(i?=?0;?i?10;?++i)?...
?
避免在聲明中使用函數(shù)調(diào)用來賦值變量,除了單個變量
?
void a(void)?{ ????/*?Avoid?function?calls?when?declaring?variable?*/ ????int32_t?a,?b?=?sum(1,?2); ????/*?Use?this?*/ ????int32_t?a,?b; ????b?=?sum(1,?2); ????/*?This?is?ok?*/ ????uint8_t?a?=?3,?b?=?4; }
?
除了char、float或double之外,始終使用stdint.h標準庫中聲明的類型。例如,8位的uint8_t等
不要使用stdbool.h庫。分別使用1或0表示真或假
?
/*?OK?*/ uint8_t?status; status?=?0; /*?Wrong?*/ #include?bool?status?=?true;
?
永遠不要與真實相比較。例如,使用if(check_func()){…}替換if (check_func() == 1)
總是將指針與空值進行比較
?
void*?ptr; /*?...?*/ /*?OK,?compare?against?NULL?*/ if?(ptr?==?NULL?||?ptr?!=?NULL)?{ } /*?Wrong?*/ if?(ptr?||?!ptr)?{ }
?
總是使用前增量(和遞減),而不是后增量(和遞減)
?
int32_t?a?=?0; ... a++;????????????/*?Wrong?*/ ++a;????????????/*?OK?*/ for?(size_t?j?=?0;?j?10;?++j)?{}??/*?OK?*/
?
總是使用size_t作為長度或大小變量
如果函數(shù)不應該修改指針所指向的內(nèi)存,則總是使用const作為指針
如果不應該修改函數(shù)的形參或變量,則總是使用const
?
/*?When?d?could?be?modified,?data?pointed?to?by?d?could?not?be?modified?*/ void my_func(const?void*?d)?{ } /*?When?d?and?data?pointed?to?by?d?both?could?not?be?modified?*/ void my_func(const?void*?const?d)?{ } /*?Not?required,?it?is?advised?*/ void my_func(const?size_t?len)?{ } /*?When?d?should?not?be?modified?inside?function,?only?data?pointed?to?by?d?could?be?modified?*/ void my_func(void*?const?d)?{ }
?
當函數(shù)可以接受任何類型的指針時,總是使用void *,不要使用uint8_t *。函數(shù)在實現(xiàn)時必須注意正確的類型轉換
?
/* ?*?To?send?data,?function?should?not?modify?memory?pointed?to?by?`data`?variable ?*?thus?`const`?keyword?is?important ?* ?*?To?send?generic?data?(or?to?write?them?to?file) ?*?any?type?may?be?passed?for?data, ?*?thus?use?`void?*` ?*/ /*?OK?example?*/ void send_data(const?void*?data,?size_t?len)?{?/*?OK?*/ ????/*?Do?not?cast?`void?*`?or?`const?void?*`?*/ ????const?uint8_t*?d?=?data;/*?Function?handles?proper?type?for?internal?usage?*/ } void send_data(const?void*?data,?int?len)?{????/*?Wrong,?not?not?use?int?*/ }
?
總是使用括號和sizeof操作符
不要使用變長數(shù)組。使用動態(tài)內(nèi)存分配代替標準C malloc和自由函數(shù),或者如果庫/項目提供了自定義內(nèi)存分配,使用它的實現(xiàn)
看看LwMEM,一個自定義內(nèi)存管理庫。
?
/*?OK?*/ #include?void my_func(size_t?size)?{ ????int32_t*?arr; ????arr?=?malloc(sizeof(*arr)?*?n);?/*?OK,?Allocate?memory?*/ ????arr?=?malloc(sizeof?*arr?*?n);??/*?Wrong,?brackets?for?sizeof?operator?are?missing?*/ ????if?(arr?==?NULL)?{ ????????/*?FAIL,?no?memory?*/ ????} ????free(arr);??/*?Free?memory?after?usage?*/ } /*?Wrong?*/ void my_func(size_t?size)?{ ????int32_t?arr[size];??/*?Wrong,?do?not?use?VLA?*/ }
?
總是將variable與0進行比較,除非它被視為布爾類型
永遠不要將布爾處理的變量與0或1進行比較。用NOT(!)代替
?
size_t?length?=?5;??/*?Counter?variable?*/ uint8_t?is_ok?=?0;??/*?Boolean-treated?variable?*/ if?(length)?????????/*?Wrong,?length?is?not?treated?as?boolean?*/ if?(length?>?0)?????/*?OK,?length?is?treated?as?counter?variable?containing?multi?values,?not?only?0?or?1?*/ if?(length?==?0)????/*?OK,?length?is?treated?as?counter?variable?containing?multi?values,?not?only?0?or?1?*/ if?(is_ok)??????????/*?OK,?variable?is?treated?as?boolean?*/ if?(!is_ok)?????????/*?OK,?-||-?*/ if?(is_ok?==?1)?????/*?Wrong,?never?compare?boolean?variable?against?1!?*/ if?(is_ok?==?0)?????/*?Wrong,?use?!?for?negative?check?*/
?
對于注釋,總是使用/* comment */,即使是單行注釋
在頭文件中總是包含帶有extern關鍵字的c++檢查
每個函數(shù)都必須包含doxygen-enabled注釋,即使函數(shù)是靜態(tài)的
使用英文名稱/文本的函數(shù),變量,注釋
變量使用小寫字母
如果變量包含多個名稱,請使用下劃線。force_redraw。不要使用forceRedraw
對于C標準庫的包含文件,請始終使用<和>。例如,# include < stdlib.h >
對于自定義庫,請始終使用""。例如,# include“my_library.h”
當轉換為指針類型時,總是將星號與類型對齊,例如。uint8_t* t = (uint8_t*)var_width_diff_type
始終尊重項目或庫中已經(jīng)使用的代碼風格
注釋
不允許以//開頭的注釋??偸鞘褂?* comment */,即使是單行注釋
?
//This?is?comment?(wrong) /*?This?is?comment?(ok)?*/
?
對于多行注釋,每行使用空格+星號
?
/* ?*?This?is?multi-line?comments, ?*?written?in?2?lines?(ok) ?*/ /** ?*?Wrong,?use?double-asterisk?only?for?doxygen?documentation ?*/ /* *?Single?line?comment?without?space?before?asterisk?(wrong) */ /* ?*?Single?line?comment?in?multi-line?configuration?(wrong) ?*/ /*?Single?line?comment?(ok)?*/
?
注釋時使用12個縮進(12 * 4個空格)偏移量。如果語句大于12個縮進,將注釋4-空格對齊(下面的例子)到下一個可用縮進
?
void my_func(void)?{ ????char?a,?b; ????a?=?call_func_returning_char_a(a);??????????/*?This?is?comment?with?12*4?spaces?indent?from?beginning?of?line?*/ ????b?=?call_func_returning_char_a_but_func_name_is_very_long(a);???/*?This?is?comment,?aligned?to?4-spaces?indent?*/ }
?
函數(shù)
每個可以從模塊外部訪問的函數(shù)都必須包含函數(shù)原型(或聲明)
函數(shù)名必須小寫,可以用下劃線_分隔
?
/*?OK?*/ void?my_func(void); void?myfunc(void); /*?Wrong?*/ void?MYFunc(void); void?myFunc();
?
當函數(shù)返回指針時,將星號對齊到返回類型
?
/*?OK?*/ const?char*?my_func(void); my_struct_t*?my_func(int32_t?a,?int32_t?b); /*?Wrong?*/ const?char?*my_func(void); my_struct_t?*?my_func(void);
?
對齊所有的功能原型(使用相同/相似的功能)以提高可讀性
?
/*?OK,?function?names?aligned?*/ void????????set(int32_t?a); my_type_t???get(void); my_ptr_t*???get_ptr(void); /*?Wrong?*/ void?set(int32_t?a); const?char?*?get(void);
?
函數(shù)實現(xiàn)必須在單獨的行中包含返回類型和可選的其他關鍵字
?
/*?OK?*/ int32_t foo(void)?{ ????return?0; } /*?OK?*/ static?const?char* get_string(void)?{ ????return?"Hello?world! "; } /*?Wrong?*/ int32_t?foo(void)?{ ????return?0; }
?
變量
使變量名全部小寫,下劃線_字符可選
?
/*?OK?*/ int32_t?a; int32_t?my_var; int32_t?myvar; /*?Wrong?*/ int32_t?A; int32_t?myVar; int32_t?MYVar;
?
按類型將局部變量分組在一起
?
void foo(void)?{ ????int32_t?a,?b;???/*?OK?*/ ????char?a; ????char?b;?????????/*?Wrong,?char?type?already?exists?*/ }
?
不要在第一個可執(zhí)行語句之后聲明變量
?
void foo(void)?{ ????int32_t?a; ????a?=?bar(); ????int32_t?b;??????/*?Wrong,?there?is?already?executable?statement?*/ }
?
你可以在下一個縮進級別中聲明新的變量
?
int32_t?a,?b; a?=?foo(); if?(a)?{ ????int32_t?c,?d;???/*?OK,?c?and?d?are?in?if-statement?scope?*/ ????c?=?foo(); ????int32_t?e;??????/*?Wrong,?there?was?already?executable?statement?inside?block?*/ }
?
用星號聲明指針變量與類型對齊
?
/*?OK?*/ char*?a; /*?Wrong?*/ char?*a; char?*?a;
?
當聲明多個指針變量時,可以使用星號對變量名進行聲明
?
/*?OK?*/ char?*p,?*n;
?
結構、枚舉類型定義
結構名或枚舉名必須小寫,單詞之間有下劃線_字符
結構或枚舉可以包含typedef關鍵字
所有結構成員都必須小寫
所有枚舉成員必須是大寫的
結構/枚舉必須遵循doxygen文檔語法
在聲明結構體時,它可以使用以下三種不同的選項之一:
1、當結構體僅用名稱聲明時,它的名稱后不能包含_t后綴。
?
struct?struct_name?{ ????char*?a; ????char?b; };
?
2、當只使用typedef聲明結構時,它的名稱后面必須包含_t后綴。
?
typedef?struct?{ ????char*?a; ????char?b; }?struct_name_t;
?
3、當結構用name和typedef聲明時,它不能包含_t作為基本名稱,它必須在它的名稱后面包含_t后綴作為typedef部分。
?
typedef?struct?struct_name?{ ????char*?a; ????char?b; ????char?c; }?struct_name_t;
?
錯誤聲明的例子及其建議的糾正:
?
/*?a?and?b?must?be?separated?to?2?lines?*/ /*?Name?of?structure?with?typedef?must?include?_t?suffix?*/ typedef?struct?{ ????int32_t?a,?b; }?a; /*?Corrected?version?*/ typedef?struct?{ ????int32_t?a; ????int32_t?b; }?a_t; /*?Wrong?name,?it?must?not?include?_t?suffix?*/ struct?name_t?{ ????int32_t?a; ????int32_t?b; }; /*?Wrong?parameters,?must?be?all?uppercase?*/ typedef?enum?{ ????MY_ENUM_TESTA, ????my_enum_testb, }?my_enum_t;
?
在聲明時初始化結構時,使用C99初始化風格
?
/*?OK?*/ a_t?a?=?{ ????.a?=?4, ????.b?=?5, }; /*?Wrong?*/ a_t?a?=?{1,?2};
?
當為函數(shù)句柄引入new typedef時,使用_fn后綴
?
/*?Function?accepts?2?parameters?and?returns?uint8_t?*/ /*?Name?of?typedef?has?`_fn`?suffix?*/ typedef?uint8_t?(*my_func_typedef_fn)(uint8_t?p1,?const?char*?p2);
?
復合語句
每個復合語句必須包括左花括號和右花括號,即使它只包含1個嵌套語句
每個復合語句必須包含單個縮進;嵌套語句時,每個嵌套包含1個縮進大小
?
/*?OK?*/ if?(c)?{ ????do_a(); }?else?{ ????do_b(); } /*?Wrong?*/ if?(c) ????do_a(); else ????do_b(); /*?Wrong?*/ if?(c)?do_a(); else?do_b();
?
在if或if-else-if語句的情況下,else必須與第一條語句的右括號在同一行
?
/*?OK?*/ if?(a)?{ }?else?if?(b)?{ }?else?{ } /*?Wrong?*/ if?(a)?{ } else?{ } /*?Wrong?*/ if?(a)?{ } else { }
?
在do-while語句的情況下,while部分必須與do部分的右括號在同一行
?
/*?OK?*/ do?{ ????int32_t?a; ????a?=?do_a(); ????do_b(a); }?while?(check()); /*?Wrong?*/ do { /*?...?*/ }?while?(check()); /*?Wrong?*/ do?{ /*?...?*/ } while?(check());
?
每一個開括號都需要縮進
?
if?(a)?{ ????do_a(); }?else?{ ????do_b(); ????if?(c)?{ ????????do_c(); ????} }
?
不要做沒有花括號的復合語句,即使是單個語句。下面的例子展示了一些不好的做法
?
if?(a)?do_b(); else?do_c(); if?(a)?do_a();?else?do_b();
?
空while循環(huán)、do-while循環(huán)或for循環(huán)必須包含花括號
?
/*?OK?*/ while?(is_register_bit_set())?{} /*?Wrong?*/ while?(is_register_bit_set()); while?(is_register_bit_set())?{?} while?(is_register_bit_set())?{ }
?
如果while(或for、do-while等)為空(嵌入式編程中也可能是這種情況),請使用空的單行括號
?
/*?Wait?for?bit?to?be?set?in?embedded?hardware?unit uint32_t*?addr?=?HW_PERIPH_REGISTER_ADDR; /*?Wait?bit?13?to?be?ready?*/ while?(*addr?&?(1?<13))?{}????????/*?OK,?empty?loop?contains?no?spaces?inside?curly?brackets?*/ while?(*addr?&?(1?<13))?{?}???????/*?Wrong?*/ while?(*addr?&?(1?<13))?{?????????/*?Wrong?*/ } while?(*addr?&?(1?<13));??????????/*?Wrong,?curly?brackets?are?missing.?Can?lead?to?compiler?warnings?or?unintentional?bugs?*/
?
盡量避免在循環(huán)塊內(nèi)遞增變量,參見示例
?
/*?Not?recommended?*/ int32_t?a?=?0; while?(a?10)?{ ????. ????.. ????... ????++a; } /*?Better?*/ for?(size_t?a?=?0;?a?10;?++a)?{ } /*?Better,?if?inc?may?not?happen?in?every?cycle?*/ for?(size_t?a?=?0;?a?10;?)?{ ????if?(...)?{ ????????++a; ????} }
?
分支語句
為每個case語句添加單個縮進
使用額外的單縮進break語句在每個case或default
?
/*?OK,?every?case?has?single?indent?*/ /*?OK,?every?break?has?additional?indent?*/ switch?(check())?{ ????case?0: ????????do_a(); ????????break; ????case?1: ????????do_b(); ????????break; ????default: ????????break; } /*?Wrong,?case?indent?missing?*/ switch?(check())?{ case?0: ????do_a(); ????break; case?1: ????do_b(); ????break; default: ????break; } /*?Wrong?*/ switch?(check())?{ ????case?0: ????????do_a(); ????break;??????/*?Wrong,?break?must?have?indent?as?it?is?under?case?*/ ????case?1: ????do_b();?????/*?Wrong,?indent?under?case?is?missing?*/ ????break; ????default: ????????break; }
?
總是包含default語句
?
/*?OK?*/ switch?(var)?{ ????case?0: ????????do_job(); ????????break; ????default:?break; } /*?Wrong,?default?is?missing?*/ switch?(var)?{ ????case?0: ????????do_job(); ????????break; }
?
如果需要局部變量,則使用花括號并在里面放入break語句。將左花括號放在case語句的同一行
?
switch?(a)?{ ????/*?OK?*/ ????case?0:?{ ????????int32_t?a,?b; ????????char?c; ????????a?=?5; ????????/*?...?*/ ????????break; ????} ????/*?Wrong?*/ ????case?1: ????{ ????????int32_t?a; ????????break; ????} ????/*?Wrong,?break?shall?be?inside?*/ ????case?2:?{ ????????int32_t?a; ????} ????break; }
?
宏和預處理指令
總是使用宏而不是文字常量,特別是對于數(shù)字
所有的宏必須是全大寫的,并帶有下劃線_字符(可選),除非它們被明確標記為function,將來可能會被常規(guī)函數(shù)語法替換
?
/*?OK?*/ #define?MY_MACRO(x)?????????((x)?*?(x)) /*?Wrong?*/ #define?square(x)???????????((x)?*?(x))
?
總是用圓括號保護輸入參數(shù)
?
/*?OK?*/ #define?MIN(x,?y)???????????((x)?(y)???(x)?:?(y)) /*?Wrong?*/ #define?MIN(x,?y)???????????x??
總是用括號保護最終的宏計算
?
/*?Wrong?*/ #define?MIN(x,?y)???????????(x)?(y)???(x)?:?(y) #define?SUM(x,?y)???????????(x)?+?(y) /*?Imagine?result?of?this?equation?using?wrong?SUM?implementation?*/ int32_t?x?=?5?*?SUM(3,?4);??/*?Expected?result?is?5?*?7?=?35?*/ int32_t?x?=?5?*?(3)?+?(4);??/*?It?is?evaluated?to?this,?final?result?=?19?which?is?not?what?we?expect?*/ /*?Correct?implementation?*/ #define?MIN(x,?y)???????????((x)?(y)???(x)?:?(y)) #define?SUM(x,?y)???????????((x)?+?(y))?
當宏使用多個語句時,使用do-while(0)語句保護它
?
typedef?struct?{ ????int32_t?px,?py; }?point_t; point_t?p;??????????????????/*?Define?new?point?*/ /*?Wrong?implementation?*/ /*?Define?macro?to?set?point?*/ #define?SET_POINT(p,?x,?y)??(p)->px?=?(x);?(p)->py?=?(y)????/*?2?statements.?Last?one?should?not?implement?semicolon?*/ SET_POINT(&p,?3,?4);????????/*?Set?point?to?position?3,?4.?This?evaluates?to...?*/ (&p)->px?=?(3);?(&p)->py?=?(4);?/*?...?to?this.?In?this?example?this?is?not?a?problem.?*/ /*?Consider?this?ugly?code,?however?it?is?valid?by?C?standard?(not?recommended)?*/ if?(a)??????????????????????/*?If?a?is?true?*/ ????if?(b)??????????????????/*?If?b?is?true?*/ ????????SET_POINT(&p,?3,?4);/*?Set?point?to?x?=?3,?y?=?4?*/ ????else ????????SET_POINT(&p,?5,?6);/*?Set?point?to?x?=?5,?y?=?6?*/ /*?Evaluates?to?code?below.?Do?you?see?the?problem??*/ if?(a) ????if?(b) ????????(&p)->px?=?(3);?(&p)->py?=?(4); ????else ????????(&p)->px?=?(5);?(&p)->py?=?(6); /*?Or?if?we?rewrite?it?a?little?*/ if?(a) ????if?(b) ????????(&p)->px?=?(3); ????????(&p)->py?=?(4); ????else ????????(&p)->px?=?(5); ????????(&p)->py?=?(6); /* ?*?Ask?yourself?a?question:?To?which?`if`?statement?`else`?keyword?belongs? ?* ?*?Based?on?first?part?of?code,?answer?is?straight-forward.?To?inner?`if`?statement?when?we?check?`b`?condition ?*?Actual?answer:?Compilation?error?as?`else`?belongs?nowhere ?*/ /*?Better?and?correct?implementation?of?macro?*/ #define?SET_POINT(p,?x,?y)??do?{?(p)->px?=?(x);?(p)->py?=?(y);?}?while?(0)????/*?2?statements.?No?semicolon?after?while?loop?*/ /*?Or?even?better?*/ #define?SET_POINT(p,?x,?y)??do?{???????/*?Backslash?indicates?statement?continues?in?new?line?*/ ????(p)->px?=?(x);?????????????????? ????(p)->py?=?(y);?????????????????? }?while?(0)?????????????????????????????/*?2?statements.?No?semicolon?after?while?loop?*/ /*?Now?original?code?evaluates?to?*/ if?(a) ????if?(b) ????????do?{?(&p)->px?=?(3);?(&p)->py?=?(4);?}?while?(0); ????else ????????do?{?(&p)->px?=?(5);?(&p)->py?=?(6);?}?while?(0); /*?Every?part?of?`if`?or?`else`?contains?only?`1`?inner?statement?(do-while),?hence?this?is?valid?evaluation?*/ /*?To?make?code?perfect,?use?brackets?for?every?if-ifelse-else?statements?*/ if?(a)?{????????????????????/*?If?a?is?true?*/ ????if?(b)?{????????????????/*?If?b?is?true?*/ ????????SET_POINT(&p,?3,?4);/*?Set?point?to?x?=?3,?y?=?4?*/ ????}?else?{ ????????SET_POINT(&p,?5,?6);/*?Set?point?to?x?=?5,?y?=?6?*/ ????} }?
不縮進子語句內(nèi)#if語句
?
/*?OK?*/ #if?defined(XYZ) #if?defined(ABC) /*?do?when?ABC?defined?*/ #endif?/*?defined(ABC)?*/ #else?/*?defined(XYZ)?*/ /*?Do?when?XYZ?not?defined?*/ #endif?/*?!defined(XYZ)?*/ /*?Wrong?*/ #if?defined(XYZ) ????#if?defined(ABC) ????????/*?do?when?ABC?defined?*/ ????#endif?/*?defined(ABC)?*/ #else?/*?defined(XYZ)?*/ ????/*?Do?when?XYZ?not?defined?*/ #endif?/*?!defined(XYZ)?*/?
文檔
文檔化的代碼允許doxygen解析和通用的html/pdf/latex輸出,因此正確地執(zhí)行是非常重要的。
對變量、函數(shù)和結構/枚舉使用doxygen支持的文檔樣式
經(jīng)常使用作為doxygen,不要使用@
始終使用5x4空格(5個制表符)作為文本行開始的偏移量
?
/** ?*?rief???????????Holds?pointer?to?first?entry?in?linked?list ?*??????????????????Beginning?of?this?text?is?5?tabs?(20?spaces)?from?beginning?of?line ?*/ static type_t*?list;?
每個結構/枚舉成員都必須包含文檔
注釋的開頭使用12x4空格偏移量
?
/** ?*?rief???????????This?is?point?struct ?*? ote????????????This?structure?is?used?to?calculate?all?point ?*??????????????????????related?stuff ?*/ typedef?struct?{ ????int32_t?x;??????????????????????????????????/*!?
函數(shù)的文檔必須在函數(shù)實現(xiàn)中編寫(通常是源文件)
函數(shù)必須包括簡要和所有參數(shù)文檔
如果每個參數(shù)分別為in或out輸入和輸出,則必須注意
如果函數(shù)返回某個值,則必須包含返回形參。這不適用于void函數(shù)
函數(shù)可以包含其他doxygen關鍵字,如note或warning
在參數(shù)名和描述之間使用冒號:
?
/** ?*?rief???????????Sum?`2`?numbers ?*?param[in]???????a:?First?number ?*?param[in]???????b:?Second?number ?*? eturn??????????Sum?of?input?values ?*/ int32_t sum(int32_t?a,?int32_t?b)?{ ????return?a?+?b; } /** ?*?rief???????????Sum?`2`?numbers?and?write?it?to?pointer ?*? ote????????????This?function?does?not?return?value,?it?stores?it?to?pointer?instead ?*?param[in]???????a:?First?number ?*?param[in]???????b:?Second?number ?*?param[out]??????result:?Output?variable?used?to?save?result ?*/ void void_sum(int32_t?a,?int32_t?b,?int32_t*?result)?{ ????*result?=?a?+?b; }?
如果函數(shù)返回枚舉的成員,則使用ref關鍵字指定哪個成員
?
/** ?*?rief???????????My?enumeration ?*/ typedef?enum?{ ????MY_ERR,?????????????????????????????????????/*!?
對常量或數(shù)字使用符號(' NULL ' => NULL)
?
/** ?*?rief???????????Get?data?from?input?array ?*?param[in]???????in:?Input?data ?*? eturn??????????Pointer?to?output?data?on?success,?`NULL`?otherwise ?*/ const?void?* get_data(const?void*?in)?{ ????return?in; }?
宏的文檔必須包括hideinitializer doxygen命令
?
/** ?*?rief???????????Get?minimal?value?between?`x`?and?`y` ?*?param[in]???????x:?First?value ?*?param[in]???????y:?Second?value ?*? eturn??????????Minimal?value?between?`x`?and?`y` ?*?hideinitializer ?*/ #define?MIN(x,?y)???????((x)?(y)???(x)?:?(y))?
頭/源文件
在文件末尾留下一個空行
每個文件都必須包括文件的doxygen注釋和后跟空行的簡要描述(使用doxygen時)
?
/** ?*?file????????????template.h ?*?rief???????????Template?include?file ?*/ ????????????????????/*?Here?is?empty?line?*/?
每個文件(頭文件或源文件)必須包含許可證(開始注釋包括單個星號,因為doxygen必須忽略這個)
使用與項目/庫已經(jīng)使用的相同的許可證
?
/** ?*?file????????????template.h ?*?rief???????????Template?include?file ?*/ /* ?*?Copyright?(c)?year?FirstName?LASTNAME ?* ?*?Permission?is?hereby?granted,?free?of?charge,?to?any?person ?*?obtaining?a?copy?of?this?software?and?associated?documentation ?*?files?(the?"Software"),?to?deal?in?the?Software?without?restriction, ?*?including?without?limitation?the?rights?to?use,?copy,?modify,?merge, ?*?publish,?distribute,?sublicense,?and/or?sell?copies?of?the?Software, ?*?and?to?permit?persons?to?whom?the?Software?is?furnished?to?do?so, ?*?subject?to?the?following?conditions: ?* ?*?The?above?copyright?notice?and?this?permission?notice?shall?be ?*?included?in?all?copies?or?substantial?portions?of?the?Software. ?* ?*?THE?SOFTWARE?IS?PROVIDED?"AS?IS",?WITHOUT?WARRANTY?OF?ANY?KIND, ?*?EXPRESS?OR?IMPLIED,?INCLUDING?BUT?NOT?LIMITED?TO?THE?WARRANTIES ?*?OF?MERCHANTABILITY,?FITNESS?FOR?A?PARTICULAR?PURPOSE ?*?AND?NONINFRINGEMENT.?IN?NO?EVENT?SHALL?THE?AUTHORS?OR?COPYRIGHT ?*?HOLDERS?BE?LIABLE?FOR?ANY?CLAIM,?DAMAGES?OR?OTHER?LIABILITY, ?*?WHETHER?IN?AN?ACTION?OF?CONTRACT,?TORT?OR?OTHERWISE,?ARISING ?*?FROM,?OUT?OF?OR?IN?CONNECTION?WITH?THE?SOFTWARE?OR?THE?USE?OR ?*?OTHER?DEALINGS?IN?THE?SOFTWARE. ?* ?*?This?file?is?part?of?library_name. ?* ?*?Author:??????????FirstName?LASTNAME??*/ ?
頭文件必須包含保護符#ifndef
頭文件必須包含c++檢查
在c++檢查之外包含外部頭文件
首先用STL C文件包含外部頭文件,然后是應用程序自定義文件
頭文件必須包含其他所有頭文件,以便正確編譯,但不能包含更多頭文件(如果需要,.c應該包含其余的頭文件)
頭文件必須只公開模塊公共變量/類型/函數(shù)
在頭文件中使用extern作為全局模塊變量,稍后在源文件中定義它們
?
/*?file.h?...?*/ #ifndef?... extern?int32_t?my_variable;?/*?This?is?global?variable?declaration?in?header?*/ #endif /*?file.c?...?*/ int32_t?my_variable;????????/*?Actually?defined?in?source?*/?
不要把.c文件包含在另一個.c文件中
.c文件應該首先包含相應的.h文件,然后是其他文件,除非另有明確的必要
在頭文件中不包含模塊私有聲明
頭文件示例(示例中沒有l(wèi)icense)
?
/*?License?comes?here?*/ #ifndef?TEMPLATE_HDR_H #define?TEMPLATE_HDR_H /*?Include?headers?*/ #ifdef?__cplusplus extern?"C"?{ #endif?/*?__cplusplus?*/ /*?File?content?here?*/ #ifdef?__cplusplus } #endif?/*?__cplusplus?*/ #endif?/*?TEMPLATE_HDR_H?*/?
審核編輯:黃飛
?
評論
查看更多