跳轉到內容

ROSE 編譯器框架/編碼規範

來自華夏公益教科書,開放的世界,開放的書籍

預期內容和避免內容

[編輯 | 編輯原始碼]

此頁面記錄了我們在 ROSE 專案中編寫程式碼的當前推薦做法。它也作為我們 程式碼審查 過程的指南。

新程式碼應該從一開始就遵循本檔案中描述的約定。

對遵循不同編碼風格的現有程式碼的更新,只有在您是程式碼維護者時才應執行。

編碼規範中各個章節的順序遵循自上而下的方法:首先是大的內容,然後深入到細粒度細節。

六項原則

[編輯 | 編輯原始碼]

我們使用編碼規範來反映我們對所有對 ROSE 的貢獻所重視的原則

  • 文件:提交的內容是什麼?這是否反映在提交資訊、自述檔案、原始碼註釋或同一個提交中的 LaTex 檔案中?
  • 樣式:編碼樣式是否與要求的和推薦的格式一致?程式碼是否乾淨、令人愉悅且易於閱讀?
  • 介面:程式碼是否具有乾淨且簡單的介面供使用者使用?
  • 演算法:程式碼是否對所使用的演算法有足夠的註釋?演算法是否正確且高效(空間和時間複雜度)?
  • 實現:實現是否正確地實現了已記錄的演算法?
  • 測試:程式碼是否附帶相應的測試轉換器和輸入,以確保貢獻做了它們應該做的事情?
    • Jenkins 是否已配置為觸發這些測試?開發者工作站上的本地測試不算。

避免編碼規範之爭

[編輯 | 編輯原始碼]

我們直接引用來自 http://www.parashift.com/c++-faq/coding-std-wars.html 的文字,如下所示

"幾乎每個軟體工程師都曾在某個時候被利用過,有人將編碼規範作為權力遊戲。對瑣碎細節的教條主義是智力薄弱的表現。不要像他們一樣。這些人是那些無法以任何有意義的方式做出貢獻的人,他們無法真正提高軟體產品的價值,所以他們沒有透過沉默暴露自己的無能,而是熱心地喋喋不休關於微不足道的事情。他們無法在軟體的實質內容中添加價值,所以他們爭論形式。僅僅因為“他們”這樣做並不意味著編碼規範是壞的,然而。

另一種對編碼規範的情緒化反應是由具有過時技能的個人制定的編碼規範造成的。例如,有人可能根據 N 十年前的程式設計方式來設定今天的標準,當時標準設定者正在編寫程式碼。這種強加會產生一種對編碼規範的不信任態度。如上所述,如果您被迫忍受過這樣的不幸經歷,不要讓它讓您對編碼規範的全部目的和價值感到厭惡。並不需要非常大的組織才能發現保持一致性的價值,因為不同的程式設計師可以編輯相同的程式碼,而無需不斷地重新組織彼此的程式碼,進行關於“最佳”編碼規範的拉鋸戰。"

必須、應該和可以

[編輯 | 編輯原始碼]

術語必須、應該和可以具有特殊含義。

  • 必須的要求必須遵守,
  • 應該是一個強烈的建議,
  • 可以是一個一般的指南。

有了新想法和建議

[編輯 | 編輯原始碼]

這不是一個記錄將來的新想法/概念/建議的地方。如果您有建議,請放入此頁面的討論選項卡 連結

我們歡迎您提出改進和更改的建議,以便我們能夠更快更好地完成工作。

Git 慣例

[編輯 | 編輯原始碼]

名稱和電子郵件

[編輯 | 編輯原始碼]

在提交本地更改之前,您必須確保已正確配置作者和電子郵件資訊(在您所有機器上)。擁有可識別且一致的姓名和電子郵件將使我們更容易評估您對我們專案的貢獻。

指南

  • 姓名:您必須使用您通常用於工作/商業的正式姓名,而不是同事、經理或贊助商難以識別的暱稱或別名。
  • 電子郵件:您必須使用您通常用於工作的電子郵件。如果確實經常使用該個人電子郵件進行商務目的,則可以是您的公司電子郵件或您的個人電子郵件(gmail)。

檢查作者和電子郵件是否配置正確

  $ git config user.name
  <your name>

  $ git config user.email
  <your email>

或者,您也可以鍵入以下內容來列出您當前所有 git 配置變數和值,包括姓名和電子郵件資訊。

  $ git config -l


設定您的姓名和電子郵件

  $ git config --global user.name "<Your Name>"
  $ git config --global user.email "<your@email.com>"

提交資訊

[編輯 | 編輯原始碼]

擁有簡潔準確的提交資訊對於幫助程式碼審查人員完成他們的工作非常重要。

最新要求

示例提交資訊,摘自 連結

(Binary Analysis) SMT solver statistics; documentation

* Replaced the SMT class-wide number-of-calls statistic with a
  more flexible and extensible design that also tracks the amount
  of I/O between ROSE and the SMT solver.  The new method tracks
  statistics on a per-solver basis as well as a class-wide basis, and
  allows the statistics to be reset at arbitrary points by the user.

* More documentation for the new memory cell, memory state, and X86
  register state classes.
  • (必需) 摘要:提交資訊的第 1 行是提交的一個簡短的單行摘要(<50 個字)。以一個主題開頭,用括號括起來,以指示此提交代表的專案、功能、錯誤修復等。
  • (可選)使用一個專案符號列表(使用星號,*)對於每個專案來詳細說明提交

另請參閱 http://spheredev.org/wiki/Git_for_the_lazy#Writing_good_commit_messages.

設計文件

[編輯 | 編輯原始碼]

“軟體設計文件是您、您的團隊、您的專案經理和您的客戶之間的書面協議。當您記錄您的假設、決定和風險時,它會讓團隊成員和利益相關者有機會達成一致意見或要求澄清和修改。一旦軟體設計文件得到相關各方的批准,它就成為限制專案範圍變更的基線。” - 如何編寫軟體設計文件 | eHow.com

我們仍在定義設計文件的要求,但初步而言,以下是在為 ROSE 模組(分析、轉換、最佳化等)編寫設計文件時應遵循的初始規則。

(我們感謝 維韋克·薩卡爾教授萊斯大學 對一些初始設計文件要求提出的富有洞察力的意見。)

  • 所有新的 ROSE 分析、轉換和最佳化必須有相應的同行評審設計文件,然後才能開始實際實現。
  • 要足夠具體,以便具有 ROSE 技能但不是原始設計人員的人員(原則上)只需檢視文件即可實現設計。
  • 預計不同的開發人員將在資料結構等方面做出不同的底層選擇

需求與設計文件

[編輯 | 編輯原始碼]

如果需求文件是軟體的“為什麼”,那麼技術設計文件就是“如何”。為簡單起見,我們目前將需求和設計都放在一個文件中。如果需要,我們可以提供單獨的需求分析文件。

編寫技術設計文件的目的是指導開發人員實現(並滿足)軟體的需求,它是軟體的藍圖。

文件必須

  • 用 LaTex 編寫,以便在出版物和提案中重複使用。
  • 儲存在版本控制下,以支援協作編寫。

您的文件至少應包含以下正式部分

  • 標題頁
  • 作者資訊:參與主要寫作的人員
  • 審閱者資訊:審閱和批准文件的人員
  • 目錄
  • 頁碼格式
  • 節號
  • 修訂歷史

主要部分

  • 概述
    • 解釋模組的動機和目標:該模組做什麼、目標、要解決的問題等。
  • 需求分析:該模組需要什麼
    • 定義介面:名稱空間、函式名稱、引數、返回值。其他人如何呼叫此模組並獲取返回值
    • 效能要求:時間和空間複雜度
    • 輸入/測試程式碼範圍:要支援哪些型別的語言、要支援的語言結構、要使用的基準
  • 設計注意事項
    • 假設
    • 約束
    • 權衡和侷限性:為什麼要使用該演算法、優先順序是什麼等。
    • 非標準元素:文件中任何非標準符號、形狀、縮略詞和獨特術語的定義
    • 計劃:如何實現每個要求
  • 內部軟體工作流程
    • 圖表:邏輯結構和邏輯處理步驟:必須有 UML 圖或 PowerPoint 圖
    • 虛擬碼:必須有虛擬碼來描述關鍵資料結構和高階演算法步驟
    • 示例:必須使用至少一個示例輸入程式碼來說明設計的演算法,以貫穿演算法的重要中間結果。
    • 錯誤、警報和警告訊息(可選)
  • 效能:必須進行復雜度分析。估計該模組的時間和空間複雜度,以便使用者可以瞭解預期結果
  • 可靠性(可選)
  • 相關工作:引用教科書和論文中的相關工作

開發指南

[編輯 | 編輯原始碼]
  • 編碼指南:標準和約定。
  • 標準語言和工具
  • 變數定義和使用位置說明

參考資料

[編輯 | 編輯原始碼]

待辦事項

[編輯 | 編輯原始碼]
  • 一個示例設計文件

規則

  • 所有貢獻必須附帶相應的測試翻譯器和輸入檔案,以證明貢獻按預期工作。
  • 所有測試必須由“make check”規則觸發
  • 所有測試應具有自我驗證功能,以確保生成正確的結果
  • 所有測試必須由 Jenkins 的至少一個整合測試啟用(用於檢查是否可以將某些內容合併到我們中心儲存庫的主分支中的測試作業)
    • 這將確保將來沒有提交可以破壞您的貢獻。

程式語言

[編輯 | 編輯原始碼]

核心語言

[編輯 | 編輯原始碼]

只允許使用 C++。任何其他程式語言都是個案 basis 上的例外。

問題:但是程式語言 XYZ 比 C++ 好多了,而且我真的擅長 XYZ!!!

答案:我們只允許 XYZ,如果

  • 您可以教我們團隊中至少一隻老狗(工作人員)新的技巧,以有效地使用 XYZ
  • 您將在未來 5 到 10 年內留在我們的團隊中,以維護所有用 XYZ 編寫的程式碼,如果老狗都沒有時間/興趣切換到 XYZ
  • 您可以證明 XYZ 可以與 ROSE 中現有的 C++ 程式碼良好互動

指令碼語言

[編輯 | 編輯原始碼]

只允許使用兩種指令碼語言

  • bash shell 指令碼
  • perl

再次強調,這只是工作人員的偏好,以及我們目前的情況。在一個專案中允許不受控制的指令碼語言數量,將使專案無法維護,難以學習。

命名規範

[編輯 | 編輯原始碼]

子部分的順序反映了開發週期中新增內容的從上到下的方法:從目錄 --> 檔案 --> 名稱空間 --> 等。

  • 語言:所有名稱都應該用英語編寫,因為英語是國際上開發的首選語言。
  • fileName; // NOT: filNavn

縮寫和首字母縮略詞

[編輯 | 編輯原始碼]

避免使用含糊不清的縮寫:在使用者清晰度和生產力之間取得良好的平衡。

縮寫和首字母縮略詞用作名稱時不應大寫。

  • exportHtmlSource(); // NOT: exportHTMLSource();
  • openDvdPlayer(); // NOT: openDVDPlayer();

同樣,常見的全小寫縮寫和首字母縮略詞在 CamelCase 名稱中不應以小寫字母開頭。

  • SgAsmX86Instruction // NOT: SgAsmx86Instruction
  • myIpod // NOT: myiPod

檔案/目錄

[編輯 | 編輯原始碼]

大小寫:

  • camelCasefileName.hpp: 這與 ROSE 中使用的現有名稱一致

副檔名:

  • 標頭檔案.h或者.hpp
  • 原始檔.cpp或者.cxx
    • .C應避免使用,以與不區分大小寫的檔案系統協同工作。

名稱空間

[編輯 | 編輯原始碼]
  • 名稱空間應該表示一個邏輯單元,通常封裝在特定目錄中的單個頭檔案中。
  • 名稱空間使用CamelCase,例如 SageInterface、SageBuilder 等。
    • 避免使用小寫名稱,錯誤名稱:sage_interface
  • 在名稱空間名稱中使用名詞單數,避免使用複數。
  • 使用完整詞語,避免使用縮寫。
  • 使用至少兩個詞語以減少名稱衝突。

原因:名稱空間的命名規範旨在與現有程式碼相容,並與名稱空間內的函式名稱一致。

  • CamelCase 名稱空間可以很好地與 doSomething() 結合使用,例如:NameSpace::doSomething()
  • 小寫名稱空間名稱可能看起來不一致,例如 name_space_1::doSomething()
  • ROSE 中許多現有的名稱空間已經遵循 CamelCase,如 連結 所示。

[注意] Leo:我相信這應該與 ROSE 編譯器框架/ROSE API 進一步討論。

必須使用以大寫字母開頭的混合大小寫,如SavingsAccount

  • 長度:範圍較大的變數應具有較長的名稱,範圍較小的變數可以具有較短的名稱。
  • 臨時變數用於臨時儲存(例如迴圈索引)最好保持簡短。閱讀此類變數的程式設計師應該能夠假設它的值在幾行程式碼之外不會被使用。整數的常見臨時變數是i, j, k, m, n. 或者,可以使用 ii、jj、kk、mm 和 nn,這些在查詢索引錯誤時更容易突出顯示。
  • 大小寫: camelCase--以小寫字母開頭的混合大小寫,如functionDecl
    • 變數故意以小寫字母開頭,而型別則以大寫字母開頭。因此,透過檢視第一個字母可以清楚地知道名稱是變數還是型別。

布林值

[編輯 | 編輯原始碼]

必須避免使用否定布林變數名。當這樣的名稱與邏輯否定運算子一起使用時,就會出現問題,因為這會導致雙重否定。!isNotFound 的含義並不立即明瞭。

bool isError; // NOT: isNoError
bool isFound; // NOT: isNotFound

表示物件集合的名稱應使用複數形式。這增強了可讀性,因為名稱為使用者提供了關於變數型別和可以在其元素上執行的操作的直接線索。

例如,

vector<Point> points;
int values[];

命名常量(包括列舉值):必須全部大寫,使用下劃線分隔單詞。

例如

int MAX_ITERATIONS, COLOR_RED;
double PI;

一般來說,應儘量減少使用此類常量。在許多情況下,將值實現為方法是更好的選擇。

int getMaxIterations() // NOT: MAX_ITERATIONS = 25
{
    return 25;
}

泛型變數應與其型別具有相同的名稱。這透過減少使用術語和名稱的數量來降低複雜性。此外,僅給定變數名稱,也可以輕鬆推斷出型別。如果出於某種原因,此約定似乎不適用,則強烈表明型別名稱選擇不當。

void setTopic(Topic* topic) // NOT: void setTopic(Topic* value)
                            // NOT: void setTopic(Topic* aTopic)
                            // NOT: void setTopic(Topic* t) 

void connect(Database* database) // NOT: void connect(Database* db)
                                 // NOT: void connect (Database* oracleDB)

非泛型變數具有作用。這些變數通常可以透過結合作用和型別來命名。

Point  startingPoint, centerPoint;
Name   loginName;

全域性變數

[編輯 | 編輯原始碼]

必須始終使用限定名,使用範圍解析運算子::.

例如,::mainWindow.open()::applicationContext.getName()

一般來說,應避免使用全域性變數。相反,

  • 將變數放入名稱空間
  • 使用單例物件

私有類變數

[編輯 | 編輯原始碼]

私有類變數應具有下劃線字尾。除了名稱和型別之外,變數最重要的特徵是範圍。透過使用下劃線來指示類範圍,可以輕鬆地區分類變數和區域性臨時變數。

例如,

class SomeClass {
  private:
    int length_;
}

一個問題是下劃線應該新增為字首還是字尾。兩種做法都很常見,但建議使用後者,因為它似乎最能保留名稱的可讀性。下劃線命名約定的一個副作用是,它很好地解決了為 setter 方法和建構函式找到合理的變數名稱的問題。

  void setDepth (int depth)
  {
    depth_ = depth;
  }

方法和函式

[編輯 | 編輯原始碼]

表示方法或函式的名稱:必須是動詞,並以混合大小寫編寫,以小寫字母開頭,以指示它們返回的內容和過程(空方法)之後它們所做的事情。

  • 例如 getName()、computeTotalWidth()、isEmpty()

方法名應避免重複物件名

  • 例如 line.getLength(); // NOT: line.getLineLength();

後者在類宣告中看起來很自然,但在使用中卻顯得多餘,如示例所示。

術語getset必須用於直接訪問屬性的地方。

  • 例如:employee.getName(); employee.setName(name); matrix.getElement(2, 4); matrix.setElement(2, 4, value);

術語compute可以在計算某個東西的方法中使用。

  • 例如:valueSet->computeAverage(); matrix->computeInverse()

為讀者提供立即的線索,表明這是一個可能非常耗時的操作,如果反覆使用,他可能會考慮快取結果。一致地使用該術語可以增強可讀性。

術語find可以在查詢某個東西的方法中使用。

  • 例如:vertex.findNearestVertex(); matrix.findMinElement();

為讀者提供立即的線索,表明這是一個簡單的查詢方法,涉及最少的計算。一致地使用該術語可以增強可讀性。

術語initialize可以在建立物件或概念的地方使用。

  • 例如:printer.initializeFontSet();

應優先使用美式英語的 initialize,而不是英式英語的 initialise。應避免使用縮寫 init。

對於布林變數和方法,應該使用字首is

  • 例如:isSet、isVisible、isFinished、isFound、isOpen

在某些情況下,有一些替代字首比is更適合。這些字首是hascanshould

  • bool hasLicense();
  • bool canEvaluate();
  • bool shouldSort();

引數之間應該用單個空格隔開,引數列表中不應包含前導空格或尾隨空格。

  • YESvoid foo(int x, int y)
  • NOvoid foo ( int x,int y )

目錄

[edit | edit source]

命名約定

[edit | edit source]

常用名稱列表

  • src: 用於放置原始檔、標頭檔案
  • include: 如果標頭檔案很多,不想將它們都放在 ./src 中,可以使用此目錄來放置標頭檔案。
  • tests: 用於放置測試輸入
  • docs: 放置 README 中未涵蓋的詳細文件

請使用 camelCase 命名目錄。

  • 應避免以大寫字母開頭。

首選名稱示例

  • roseExtensions
  • roseSupport
  • roseAPI

要避免的名稱

  • rose_api
  • rose_support

佈局

[edit | edit source]

TODO:有關在 ROSE git 儲存庫中放置內容的總體情況。


對於 ./projects 下的每個專案目錄,我們的約定是為不同的檔案建立子目錄。

  • README:必須要有此檔案
  • ./src:用於放置所有原始檔
  • ./include:如果不想將所有標頭檔案都放在 ./src 中,可以使用此目錄來放置標頭檔案。
  • ./tests:用於放置測試輸入檔案
  • ./doc:如果 README 不夠,可以使用此目錄來放置更詳細的文件

檔案

[edit | edit source]

單個檔案應該包含一個邏輯單元或功能。保持模組化!

命名規範

[edit | edit source]

檔名應該具體且描述性地說明其內容。

應該使用 camelCase(開頭使用小寫字母)。

  • 好的示例:fileName.h

要避免的名稱

  • 以大寫字母開頭,
  • 使用下劃線的錯誤示例:file_name.h

錯誤的檔名

  • functions.h
  • file_name.h

參考資料

行長

[edit | edit source]
  • 檔案內容應該保持在 80 列以內。

80 列是編輯器、終端模擬器、印表機和偵錯程式常用的尺寸,在多人之間共享的檔案應該保持在這些限制內。避免無意間換行,在程式設計師之間傳遞檔案時,這可以提高可讀性。如果編寫了一個超過 80 列的教程,它很可能無法在一頁上顯示。如果沒有檢視程式碼庫本身,這實際上會使教程變得毫無用處。

縮排

[edit | edit source]

除了需要使用製表符(\t)的情況(例如,Makefile),應避免使用製表符進行程式碼縮排。

建議使用 2 或 4 個空格進行程式碼縮排。

for (i = 0; i < nElements; i++) 
  a[i] = 0;

1 個空格的縮排過小,無法強調程式碼的邏輯佈局。超過 4 個空格的縮排會使巢狀過深的程式碼難以閱讀,並增加程式碼行需要拆分的可能性。

字元

[edit | edit source]
  • 必須避免使用 TAB 和分頁符等特殊字元。

在多人、多平臺的環境中使用這些字元會導致編輯器、印表機、終端模擬器或偵錯程式出現問題。

我們已經內建了一個 perl 指令碼來執行此策略。

標頭檔案

[edit | edit source]

檔名

  • 必須使用 camelCase:例如 fileName.h 或 fileName.hpp
  • 避免使用 file_name.h

字尾

  • 對於 C 標頭檔案:使用.h
  • 對於 C++ 標頭檔案:使用.h或者.hpp

必須要有

  • 受保護的預處理指令以防止標頭檔案被包含多次,例如
#ifndef _HEADER_FILE_X_H_
#define _HEADER_FILE_X_H_

#endif //_HEADER_FILE_X_H_
  • 嘗試將變數、函式、類放在描述性的名稱空間中。
  • 包含語句必須僅位於檔案頂部。
    • 透過原始檔深處的“隱藏”包含語句來避免不必要的編譯副作用。

在標頭檔案中要避免的

  • 全域性變數、函式或類 ; // 它們會汙染全域性範圍
  • using namespace std;
    • 這將汙染包含此標頭檔案的每個 .cpp 檔案的全域性範圍。using namespace 僅應由 .cpp 檔案使用。有關更多說明,請訪問 linklink2
  • 函式定義
    • 標頭檔案用於公開型別和函式介面。它們將被多個 cpp 檔案包含。標頭檔案中的函式定義將在編譯包含它的多個 cpp 檔案時導致重複定義錯誤。


參考資料

原始檔

[edit | edit source]

同樣,檔名應遵循命名約定

  • camelCase 檔名:例如 sageInterface.cpp
  • 避免使用大寫字母、空格和特殊字元

首選後綴

  • 使用.c用於 C 原始檔
  • 使用.cpp或者.cxx用於 C++ 原始檔

要避免的名稱

  • 大寫.C用於原始檔。這將在將 ROSE 移植到不區分大小寫的檔案系統時導致一些問題。

參考資料

README

[edit | edit source]

ROSE git 儲存庫中的所有主要目錄都應該有一個 README 檔案

  • projects/projectXYZ 必須有一個 README 檔案。

檔名應為 README

要避免的

  • README.txt
  • readme

必需內容

[edit | edit source]

對於 ROSE 中的所有主要目錄,應該有一個 README 檔案,解釋

  • 此目錄中包含什麼
  • 此目錄實現了什麼功能
  • 誰添加了它以及新增時間

每個專案目錄都必須有一個 README 檔案,解釋

  • 此專案是關於什麼的
    • 專案名稱
    • 動機:為什麼我們要建立這個專案
    • 目標:我們想要實現什麼
  • 設計/實現:以便下一個人能夠快速瞭解併為這個專案做出貢獻
    • 我們如何設計/實現它。
    • 主要演算法是什麼
  • 關於如何使用該專案的簡要說明
    • 安裝
    • 測試
    • 或指出在哪裡可以找到完整的文件
  • 狀態
    • 什麼有效
    • 什麼無效
  • 已知限制
  • 參考文獻和引用:用於底層演算法
  • 作者和日期

格式

[edit | edit source]

README 格式

  • 文字格式,包含清晰的章節和專案符號
  • 可選地,可以使用由 w:Markdown 定義的樣式

示例

[edit | edit source]

可以在以下位置找到一個 README 示例

原始碼文件

[edit | edit source]

ROSE 的 原始碼 使用 Doxygen 文件系統 進行 文件化

一般準則

[編輯 | 編輯原始碼]
  • 僅限英文
  • 使用有效的 Doxygen 語法(參見下面的“示例”)
  • 使程式碼對第一次閱讀程式碼的人來說易於理解
    • 記錄關鍵概念、演算法和功能
    • 涵蓋您的專案、檔案、類/名稱空間、函式和變數。
    • 明確說明您的輸入和輸出,特別是輸入或輸出的含義
      • 如果使用者不必考慮輸出的含義或輸入應該是什麼,他們更有可能使用您的程式碼
    • 聰明通常等同於混淆,在編碼中避免這種形式的聰明。

TODO,尚未準備好

  • 測試您的文件,方法是在您的機器上生成它,然後手動檢查它以確認它的正確性

TODO:生成本地文件

這有時不起作用,因為我們有一個配置檔案來指示要掃描哪些目錄以生成 Web 參考 HTML 檔案

  $ make doxygen_docs -C ${ROSE_BUILD}/docs/Rose/

使用 //TODO

[編輯 | 編輯原始碼]

這是改進程式碼註釋的推薦方法。

在進行增量開發時,通常會有一些您決定在下次迭代中做的事情,或者您知道當前的實現/功能有一些限制,需要在將來修復。

一個好方法是在您做出這種決定時立即將 TODO 源註釋(// TODO blar blar ..)放入相關程式碼中,這樣您就不會忘記下次要做什麼。

TODO 還可以作為程式碼中的一些便捷標誌,供其他人使用,如果他們想在您離開後改進您的工作。

通常一個簡短的單行註釋就足夠了

//! Brief description.

Doxygen 支援具有多行的註釋。

/**
 
   ... text..
 
 */

/**
 *
 *  ... text..
 *
 */


/*******************************//**
 *         text
*********************************/

/////////////////////////////////////
///  ... text <= 80 columns in length
//////////////////////////////////////

組合單行和多行

[編輯 | 編輯原始碼]

Doxygen 可以為函式生成簡短的註釋,並且可以選擇在使用者單擊函式時顯示詳細註釋。

以下是一些支援組合單行和多行源註釋的選項。

選項 1:

/**
 * \brief Brief description.
 *        Brief description continued.
 *
 * [Optional detailed description starts here.]
 */

選項 2:

/**
 \brief Brief description.
        Brief description continued.
 
 [Optional detailed description starts here.]
 */

---

單行註釋後跟多行註釋':

您可以使用多行註釋(選項 1 或 2)擴充套件現有的單行註釋。例如

//! Brief description.
/**
 * Detailed description starts here.
 */


TODO:提供完整的組合示例。

規則

  • 除了簡單的函式(如 getXX() 和 setXX())之外,所有其他函式都應該至少有一個行註釋來解釋它做了什麼
  • 避免使用全域性函式和全域性變數。嘗試將它們放入名稱空間中。
  • 一個函式不應該超過 100 行程式碼。請將大型函式重構為更小的獨立函式。
  • 限制無條件的 printf(),這樣您的翻譯器在處理多個輸入檔案時就不會列印數百行不必要的文字輸出
    • 使用 if 條件控制 printf(),用於除錯目的,例如“ if ( SgProject::get_verbose() > 0 ) ”
  • 函式的開頭部分應該嘗試對函式引數進行健全性檢查。

規則

  • 請遵循 Doxygen 風格註釋
  • 請詳細解釋您的函式如何工作以及演算法中的步驟。
    • 審閱者將閱讀您註釋的資訊以瞭解您的演算法,然後閱讀您的程式碼以檢視程式碼是否正確且高效地實現了演算法。

正確實現設計/記錄的演算法。未來的使用者將沒有時間直接閱讀您的程式碼來辨別它的功能。

程式碼在時間和空間(記憶體)複雜度方面都應該是有效的。

請注意,您的翻譯器可能處理數千條語句,甚至更多 AST 節點。

請注意,除了您之外的人員也可能使用您的程式碼或進一步開發它。請儘可能地做到這一點。

儘可能使用名稱空間,避免使用全域性變數或類。

名稱等於功能

[編輯 | 編輯原始碼]

以它是什麼來命名類。如果您想不出它是什麼,這是一個線索,說明您對設計思考得還不夠深入。

  • 類名應該是一個名詞。

超過三個詞的複合名詞是一個線索,說明您的設計可能在系統中混淆了各種實體。重新審視您的設計。嘗試使用 CRC 卡會議來檢視您的物件是否承擔了比應有的更多職責。

顯式訪問

[編輯 | 編輯原始碼]

所有部分(public、protected、private)都應該被明確地識別。不適用的部分應該被省略。

公共成員優先

[編輯 | 編輯原始碼]

類的各個部分應該按 public、protected 和 private 的順序排序。

排序方式是“最公共的成員優先”,因此只需要使用該類的人員在到達 protected/private 部分時就可以停止閱讀。

類變數

[編輯 | 編輯原始碼]

類變數不應宣告為 public。

公共變數違反了 C++ 資訊隱藏和封裝的概念。請改用私有變數和訪問函式。此規則的一個例外是,當該類本質上是一個數據結構時,沒有行為(等效於 C 結構)。在這種情況下,將類的例項變數設為 public 是合適的。

避免使用結構體

[編輯 | 編輯原始碼]

結構體在 C++ 中保留是為了與 C 保持相容,避免使用它們可以減少使用的結構數量,從而提高程式碼的可讀性。請改用類。

for() 結構中只能包含迴圈控制語句,其他內容不允許。

//Correct
sum = 0; 
for (i = 0; i < 100; i++) 
  sum += value[i]; sum += value[i];

//Incorrect
 for (i = 0, sum = 0; i < 100; i++) 

這提高了可維護性和可讀性。它還允許未來的開發人員清楚地區分控制內容和迴圈中的內容。

迴圈變數應該在迴圈之前立即初始化。

型別轉換

[編輯 | 編輯原始碼]

型別轉換必須始終顯式完成。永遠不要依賴隱式型別轉換。

  //Correct
  floatValue = static_cast<float>(intValue); 
  //Incorrect 
  floatValue = intValue;

透過這種方式,程式設計師表明他了解所涉及的不同型別,並且混合是故意的。

條件語句

[編輯 | 編輯原始碼]

條件語句的語句體必須放在單獨的一行。

 if (isDone) 
 // NOT: if (isDone) doCleanup(); doCleanup();

這是為了除錯目的。當在一行中寫程式碼時,無法直觀地判斷測試結果是否真的為真。

關鍵字if與條件語句之間必須有一個空格(isDone).

if (isDone)
  ^ space

避免使用複雜的條件表示式。必須引入臨時布林變數

//recommended way
bool isFinished = (elementNo < 0) || (elementNo > maxElement); 
bool isRepeatedEntry = elementNo == lastElement; 
if (isFinished || isRepeatedEntry) { : } 

// NOT: if ((elementNo < 0) || (elementNo > maxElement)|| elementNo == lastElement) { : }

透過將布林變數賦值給表示式,程式獲得了自動文件。構造將更容易閱讀、除錯和維護。當變數命名得當時,它還有助於未來的開發人員理解構造的每個部分所完成的功能。

printf 和 cout

[編輯 | 編輯原始碼]

所有螢幕輸出必須放在 if 語句中,以條件方式執行,無論是透過詳細級別還是其他除錯選項。

它們預設情況下不得列印資訊。

TODO:這可以在將來透過一個簡單的 Compass 檢查器來強制執行。

仔細區分

  • 已知允許忽略的內容和
  • 當前實現尚未處理的內容。
  switch(type->variantT())
 {
    case V_SgTypeDouble:
      {
        ...
      }
      break;
    case V_SgTypeInt:
      {
        ...
      }
      break;
   case V_SgTypeFloat: // things which are known to be allowed to be ignored.
      break;
   default:
    {
     //Things which are not yet explicitly handled
      cerr<<"warning, unhandled node type: "<< type->class_name()<<endl;
    }

鼓勵經常使用 assert 來明確表達和保證程式碼中使用的假設。

請使用 ROSE_ASSERT() 或 assert()。

對於每個斷言的出現,必須新增一個 printf 或 cerr 訊息以指示程式碼中的位置以及出錯的地方,以便使用者可以立即瞭解斷言失敗的原因,而無需透過偵錯程式來找出錯誤原因。

應避免的語句

[編輯 | 編輯原始碼]

以下語句通常應該避免

  • 不應使用 goto 語句。goto 語句違反了結構化程式碼的理念。只有極少數情況下(例如從深層巢狀結構中跳出)應該考慮使用 goto,而且只有當等效的結構化對應項可讀性較差時。
  • 應避免條件語句中的可執行語句。帶有可執行語句的條件語句非常難以閱讀。
  File* fileHandle = open(fileName, "w"); 
  if (!fileHandle) { : } 
  // NOT: if (!(fileHandle = open(fileName, "w"))) { : }

表示式

[編輯 | 編輯原始碼]

可讀性、簡單性和可除錯性的指南。

  • 三元運算子 (?:) 應替換為 if/else。
  • 長表示式應分解為幾個更簡單的語句。為沿過程獲得的每個指標值新增斷言以幫助以後除錯。
  • 應將運算子優先順序、短路求值、賦值表示式等的巧妙使用重寫為易於理解的替代形式。
  • 始終記住,未來的程式設計師會欣賞清晰簡單的程式碼,而不是模糊的聰明技巧。

AST 轉換器

[編輯 | 編輯原始碼]

所有基於 ROSE 的轉換器都應在完成所有轉換後呼叫 AstTests::runAllTests(project) 以確保轉換後的 AST 是正確的。

這比僅僅正確地反解析為可編譯程式碼具有更高的標準。AST 經常會正確地透過反解析但無法透過健全性檢查。

更多資訊請參見 健全性檢查

參考資料

[編輯 | 編輯原始碼]

我們列出了一些外部資源,這些資源對我們定義 ROSE 的編碼標準具有影響

華夏公益教科書