C 程式設計/結構和風格
本文是對 C 程式語言中良好編碼風格的基本介紹。它旨在提供有關如何有效地使用縮排、註釋和其他元素的資訊,這些元素將使您的 C 程式碼更具可讀性。它不是關於實際 C 程式設計的教程。
作為一名初學者,在程式程式碼中建立結構的意義可能並不明顯,因為編譯器並不關心其中的差異。但是,隨著程式變得複雜,編寫程式很可能已經成為一項聯合工作。(或者其他人可能想看看它是如何完成的。或者您可能需要在幾年後再次閱讀它。)編寫良好的程式碼還有助於您概述程式碼的功能。
在以下部分中,我們將嘗試解釋良好的程式設計實踐,這些實踐將使您的程式更清晰。
在 C 語言中,程式由語句組成。語句以分號結尾,並收集在稱為函式的部分中。按照慣例,語句應保留在自己的行上,如下例所示
#include <stdio.h>
int main(void) {
printf("Hello, World!\n");
return 0;
}
以下程式碼塊本質上是相同的。雖然它包含完全相同的程式碼,並且將以相同的結果進行編譯和執行,但刪除空格會導致一個本質的區別:它更難閱讀。
#include <stdio.h>
int main(void) {printf("Hello, World!\n");return 0;}
簡單地使用縮排和換行可以極大地提高程式碼的可讀性,而不會影響程式碼效能。可讀的程式碼使更容易檢視函式和過程的結束位置,以及哪些行屬於哪些迴圈和過程。
本課將重點介紹如何改進一個示例程式碼段的編碼風格,該程式碼段應用公式並列印結果。稍後,您將看到如何更詳細地編寫此類任務的程式碼。現在,重點關注程式碼的外觀,而不是它的功能。
在程式碼中新增空白無疑是良好程式碼結構中最重要的部分。有效地使用空白可以建立程式碼流的視覺尺度,這在您想要維護程式碼時返回到程式碼時非常重要。
請注意行號的使用。它們不是實際程式碼的一部分。它們僅用於參考。 |
如果換行最少,程式碼幾乎無法讓人閱讀,並且可能難以除錯或理解
#include <stdio.h>
int main(void) { int revenue = 80; int cost = 50; int roi; roi = (100 * (revenue - cost)) / cost; if (roi >= 0) { printf ("%d\n", roi); } return 0; }
與其將所有內容放在一行上,不如將長行分解,以便每個語句和宣告都放在自己的行上。插入換行符後,程式碼將如下所示
#include <stdio.h>
int main(void) {
int revenue = 80;
int cost = 50;
int roi;
roi = (100 * (revenue - cost)) / cost;
if (roi >= 0) {
printf ("%d\n", roi);
}
return 0;
}
空行應用於偏移程式碼的主要元件。始終使用它們
- 在預處理器指令之後。
- 在宣告新變數之後。
- 根據您自己的判斷,查詢其他需要分隔元件的位置。
根據這兩條規則,現在應該至少添加了兩次換行。
- 在第 1 行之後,因為第 1 行包含預處理器指令。
- 在第 5 行之後,因為第 5 行包含變數宣告。
這將使程式碼比以前更具可讀性
以下程式碼行在函式之間有換行符,但沒有縮排。
#include <stdio.h>
int main(void) {
int revenue = 80;
int cost = 50;
int roi;
roi = (100 * (revenue - cost)) / cost;
if (roi >= 0) {
printf ("%d\n", roi);
}
return 0;
}
但它仍然不如它可以的那樣易讀。
雖然在程式碼的關鍵塊之間新增簡單的換行符可以使程式碼更易於閱讀,但它沒有提供有關程式塊結構的資訊。使用 Tab 鍵可能非常有用。縮排透過將執行路徑的起始點移動到新列來視覺上分隔它們。這種簡單的做法將使程式碼更容易閱讀和理解。縮排遵循一個相當簡單的規則
- 新塊內的所有程式碼都應比前一條路徑中的程式碼縮排一個 Tab[1]。
基於上一節中的程式碼,有兩個塊需要縮排
- 第 4 行到第 16 行
- 第 13 行
#include <stdio.h>
int main(void) {
int revenue = 80;
int cost = 50;
int roi;
roi = (100 * (revenue - cost)) / cost;
if (roi >= 0) {
printf ("%d\n", roi);
}
return 0;
}
現在很明顯程式的哪些部分適合哪些塊。您可以分辨出程式設計師打算哪些部分是條件性的,哪些部分不是。雖然可能不會立即注意到,但一旦許多巢狀路徑新增到程式的結構中,縮排的使用就變得非常重要。因此,縮排使程式的結構清晰。
據稱,研究表明,2 到 4 個字元的縮排大小比 8 個字元的縮排更容易閱讀[2]。但是,某些系統可能仍在使用 8 個字元的縮排[3]。
程式碼中的註釋可用於各種目的。它們提供了最簡單的方法來設定程式碼的特定部分(及其用途);以及在程式碼的不同部分之間提供視覺“分割”。在整個程式碼中使用良好的註釋將使您更容易記住程式碼的特定部分的功能。
現代版本的 C(以及許多其他語言)中的註釋可以有兩種形式
// Single Line Comments (added by C99 standard, famously known as c++ style of comments)
和
/* Multi-Line
Comments
(only form of comments supported by C89 standard)*/
請注意,單行註釋是 C 語言中較新的新增功能,因此某些編譯器可能不支援它們。最新版本的 GCC 將能夠毫無問題地支援它們。
本節將重點介紹每種註釋形式的各種用途。
單行註釋最適合用於簡單的“旁註”,解釋程式碼的某些部分的功能。放置這些註釋的最佳位置是在變數宣告旁邊,以及在可能需要解釋的程式碼段旁邊。註釋應明確對應程式碼背後的意圖和想法。從閱讀程式碼中立即顯而易見的內容不應放在註釋中。
根據我們之前的程式,有一些很好的位置可以放置註釋
- 第 5 行和/或第 6 行,解釋“int revenue”和“int cost”分別代表什麼,
- 第 8 行,解釋變數“roi”將用於什麼,
- 第 10 行,解釋計算的想法,
- 第 12 行,解釋“if”的目的。
這將使我們的程式看起來像
#include <stdio.h>
int main(void) {
int revenue = 80; // as of 2016
int cost = 50;
int roi; // return on investment in percent
roi = (100 * (revenue - cost)) / cost; // formula from accounting book
if (roi >= 0) { // we don't care about negative roi
printf ("%d\n", roi);
}
return 0;
}
多行註釋最適合用於對程式碼進行長篇解釋。它們可用作版權/許可宣告,也可用於解釋程式碼塊的目的。這有兩個好處:它們使您的函式更容易理解,並且使更容易發現程式碼中的錯誤。如果您知道某個程式碼塊的預期功能,那麼如果發生錯誤,就更容易找到負責的程式碼段。
例如,假設我們有一個程式,其設計目的是列印“Hello, World!” 一定數量的行,並且重複指定的次數。該程式中將包含許多 for 迴圈。在本例中,我們將行數稱為 i,每行字串的數量稱為 j。
描述 'for' 迴圈 i 目的的多行註釋的一個很好的例子是
/* For Loop (int i)
Loops the following procedure i times (for number of lines). Performs 'for' loop j on each loop,
and prints a new line at end of each loop.
*/
這很好地解釋了 i 的用途,同時沒有詳細說明 j 的作用。透過詳細說明特定路徑的作用(而不是其內部的路徑),將更容易對路徑進行故障排除。
類似地,您應該始終在每個函式之前包含多行註釋,以解釋每個函式的作用、先決條件和後置條件。始終將技術細節留給程式內部的各個程式碼塊 - 這使得故障排除更容易。
函式描述符應該類似於
/* Function : int hworld (int i,int j)
Input : int i (Number of lines), int j (Number of instances per line)
Output : 0 (on success)
Procedure: Prints "Hello, World!" j times, and a new line to standard output over i lines.
*/
此係統允許快速瞭解函式應該做什麼。然後,您可以在程式的後面詳細說明程式每個方面的實現方式。
最後,如果您喜歡美觀的原始碼,多行註釋系統可以輕鬆添加註釋框。與其他方式相比,這使得註釋更加突出。它們看起來像這樣
/***************************************
* This is a multi line comment
* That is nearly surrounded by a
* Cool, starry border!
***************************************/
應用於我們的原始程式,我們現在可以包含更具描述性和可讀性的原始碼
#include <stdio.h>
int main(void) {
/************************************************************************************
* Function: int main(void)
* Input : none
* Output : Returns 0 on success
* Procedure: Prints 2016's return on investment in percent if it is not negative.
************************************************************************************/
int revenue = 80; // as of 2016
int cost = 50;
int roi; // return on investment in percent
roi = (100 * (revenue - cost)) / cost; // formula from accounting book
if (roi >= 0) { // we don't care about negative roi
printf ("%d\n", roi);
}
return 0;
}
這將允許程式的任何外部使用者輕鬆理解程式碼的功能及其操作方式。它還可以避免與其他同名函式產生混淆。
一些程式設計師在程式碼塊註釋的右側新增一列星號
/***************************************
* This is a multi line comment *
* that is completely surrounded by a *
* cool, starry border! *
***************************************/
但大多數程式設計師不會在程式碼塊註釋的右側新增任何星號。他們認為對齊右側是浪費時間。
原始檔中的註釋可以透過使用 Doxygen 等流行工具自動用於記錄原始碼。[4][5]
- ↑ 一些程式設計師建議“使用空格進行縮排。不要在程式碼中使用製表符。您應該將編輯器設定為在您按下 Tab 鍵時輸出空格。” [1] [2] 其他程式設計師則不同意。 [3] [4] 無論您是偏好空格還是製表符,請確保在您正在處理的專案中保持一致。混合使用製表符和空格會導致程式碼難以閱讀。
- ↑ http://www.oualline.com/vim/vim-cook.html#drawing Vim 食譜
- ↑ https://kernel.linux.club.tw/doc/html/latest/process/coding-style.html Linux 核心編碼風格
- ↑ "C++ 和 Java 的編碼規範"“本文件中說明的所有程式碼塊註釋在程式碼塊註釋的右側都沒有漂亮的星號。做出這個有意的選擇是因為對齊這些漂亮的星號會浪費大量時間,並且會阻礙內聯註釋的維護。”
- ↑ c2:BigBlocksOfAsterisks,"程式碼工藝" Pete Goodliffe 著,第 82 頁,Falvotech“C 程式設計風格指南”,Fedora 目錄伺服器編碼風格
- 阿拉丁的 C 編碼指南 - 一個更權威的 C 編碼指南。
- C/C++ 程式設計風格 GNU 編碼風格和 Linux 核心編碼風格