C/C++程式碼規範
C/C++程式碼規範
程式碼格式在一些語言裡不是必需的,比如C語言中,你可以在語句之間加任意個;
,可以加很多空格;可以一個語句分兩行寫,也可以把所有程式碼都放在一行。有些語言就對程式碼格式非常敏感,比如Python,同一層級的語句之間一定要有相同的縮排。
程式碼規範是在程式碼格式上更進一步的要求,為的是使程式碼更容易閱讀、出現錯誤更容易查錯。
為了程式碼的整潔、漂亮,程式碼的風格需要統一,也就是說,同一篇程式碼、同一個專案的程式碼風格需要保持一致性。一個人的風格可能是固定的,而一個專案的風格通常需要事先制定。
不同人可能持不同的程式碼風格,但是也有一些規範是大家共同遵守的。可以多閱讀已經寫好的、規範的程式碼,來熟悉一些基本的、大家共同遵守的規範。
下面將介紹一下C語言的程式碼規範大概該注意哪些地方。
縮排
縮排是非常常見的事情,它被用來顯示出程式碼的層級。一般可以用Tab
或者空格來形成縮排。
要輸入一個Tab
,只要按下鍵盤上的Tab鍵就好了。
使用Tab
做縮排,只需要一個Tab
就夠了;而使用空格做縮排,一般會使用2或4個空格為一個縮排。
根據不同的編輯器設定或個人習慣,一個Tab
可能會被顯示成2 / 4 / 8個空格等等。因此,切忌將Tab將空格(Space)和縮排(Tab)混用,這樣有可能導致程式碼顯示出來的層次變得混亂,難以閱讀。
int foo(int num) {
// 一級縮排
if (num % 2 == 0) {
// 二級縮排
return num + 1;
}
else return num;
}
大括號
一般有兩種方式,一種是左大括號“{
”放在行末,另一種是{
單獨佔一行。一般第一種更為常見。甚至,會有把else
關鍵字放在if
語句大括號的同行。
int foo(int num) {
if (num % 2 == 0) {
return num + 1;
}
else return num;
}
大括號換行的寫法:
int foo(int num)
{
if (num % 2 == 0)
{
num *= 2;
num += 1;
}
return num;
}
當然,格式都不是絕對的,可以根據情況靈活調整,只要方便閱讀就好。比如如果幾條語句比較簡單、邏輯關聯強,也可以放在一行。
<template class T>
std::vector<T> stack_reverse(std::stack<T> _stack) {
std::vector<T> result;
while (!_stack.empty()) { result.pusk_back(_stack.top()); _stack.pop(); }
return result;
}
空格
比如if
、else
、for
、while
等關鍵字後留空格,可以突出關鍵字。而相對應的,函式名後的括號要緊跟。
void print_vector_int(const std::vector<int> & a) {
for (auto i : a) std::cout << i << ' ';
std::cout << std::endl;
}
左右括號(
、)
一般緊緊包裹其中的內容,而,
、;
則緊緊跟著其左側的字元,其右側要留一個空格。
std::vector<int> a = {1, 2, 3, 4, 5};
雙目運算子(如+
、-
、=
、==
、+=
、<
、%
等)的左右都要留空格。
int num1 = 10 / 2;
int num2 = 20 % 3;
int val = num1 + num2;
單目運算子(如!
、++
、--
、*
、&
等)緊跟它的運算元,前後不留空格。
std::vector<int> a = {
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12
};
auto i = a.begin();
while (i != a.end()) {
std::cout << *i << ' ';
++i;
}
方括號[]
、成員運算子.
、->
也緊跟其運算元,即前後不留空格。
std::vector<int> a = {1, 2, 3, 4, 5};
a[0] = a[1] + a[2];
a.erase(a.begin());
int val = 10;
auto b = new std::vector<int>();
b->push_back(val);
b->erase(b->begin());
符號命名
養成良好且規範的變數 / 函式命名方式和習慣。
參考閱讀:
符號的命名主要有下劃線法、駝峰法等,比如find_first_of()
、namedWindow()
等。
巨集名和列舉名(其實列舉就可以視作一種巨集定義)一般採用全大寫+下劃線,比如BGR2GRAY
、MAX_LENGTH
、BLUE
等。
一般來說,函式、區域性變數名、全域性變數名、巨集名等,可以採用不同的命名法以區分彼此。
變數名也應具有一定的意義,比如tmp
、temp
一般表示臨時變數,i
、j
、k
等一般用作迭代,cnt
一般用來計數。
struct MyStruct {
int val_a;
int val_b;
char class_type;
enum Type {TYPE_A, TYPE_B};
bool isValid() { return val_a > 10 && val_b > 20; }
}
註釋
寫程式碼的時候記得新增一些註釋。良好的註釋可以方便自己和別人閱讀和修改程式碼。
不必要事無鉅細,在關鍵部分給出提示即可。
通常,對於一個函式應該寫明其具有的功能、函式各個引數的意義;對於變數要有對其作用的介紹。這樣性質的註釋一般寫在函式或變數的宣告處附近。而對於函式的定義部分也最好有相應的解釋,可以告訴讀者某行或某段程式碼實現了什麼事情、或者為什麼這樣寫。
很多編輯器、IDE可以識別到這些註釋,並在滑鼠懸停在它們的呼叫上時顯示出函式的原型和註釋,很是方便。
函式、變數名本身也應該體現一定的意義。如果得當,那麼程式碼則具有自述性(self-explaining),而不必要額外再寫註釋了。
不建議用中文拼音為符號命名,更不要用中文縮寫,因為中文的緣故,同音詞很多,相同拼音首字母的詞語更多,別人很難聯想到具體是什麼詞語。既然是用26個英文字母程式設計,那麼也建議使用英語給變數起名。
起變數名在一定程度上也需要一定的英語考究,比如一些詞雖然意思相近,但其中的一個會比其他的更合適。
下面是“選猴王”(也就是“約瑟夫問題”)的參考程式碼:
// return the postion number of the monkey king
int get_monkey_king(int n, int m) {
std::queue<int> monkeys_queue;
for (int i = 1; i <= n; ++i) monkeys_queue.push(i);
cnt = 0;
while (monkeys_queue.size() > 1) {
++cnt;
auto monkey = monkeys_queue.front();
monkeys_queue.pop();
if (cnt == m) cnt = 0;
else monkeys_queue.push(monkey);
}
std::cout << monkeys_queue.front() << std::endl;
}
int main() {
std::cin >> n >> m;
std::cout << get_monkey_king(n, m);
}