撰寫指引
CNTK程式碼撰寫樣式
此頁面記載CNTK原始程式碼中使用的慣例。 撰寫新程式碼時,請遵守這些慣例。 遵循常見意義並細分函式, (幾個畫面頁面) 、使用有意義的名稱、批註良好,以及讓批註和程式碼保持同步等等。
基本概念:縮排、間距和大括弧
程式碼會使用四個空格一致縮排。 不允許在程式碼中的任何位置使用 Tab 字元。 唯一的例外是 Makefiles、其他建置系統,或需要 Tab 字元的資料檔案。
下列程式碼區塊會縮排:
- 控制語句主體:for、if、while、switch 等等。
- Free 語句區塊,也就是不遵循任何控制項語句的開頭和右大括弧。 這些有時會用來限制物件的存留期。
- 類別和函式的主體。
- 語句會從上一行繼續。
- case 語句中的程式碼會在 case 語句後面一行開始,並縮排。
下列專案不會縮排:
- 命名空間的內容。
- case 標籤
- 存取控制規範。
具有 long 參數清單的函式宣告可能會分割成多行。 分割線上的參數宣告應該縮排到函式宣告的左括弧。 對具有 long 參數清單的函式呼叫可能會分割成多行,分割線應該縮排到相關聯函式語句的左括弧。
程式碼是使用 Allman 或 BSD Unix 樣式大括弧所撰寫。 此樣式會將與控制項語句相關聯的大括弧放在下一行,縮排到與控制項語句相同的層級。 大括弧內的語句會縮排到下一個層級,建議不要省略大括弧,即使是社區塊也是如此。
空格會出現在下列位置:
- 圍繞所有二元運算子,包括指派
- 在關鍵字與括弧之間
- 在識別碼或關鍵字與大括弧之間
- 在未結束行的逗號和分號之後
下列位置中沒有空格:
- 分號和逗號之前
- 括弧內部
- 在函式名稱和其引數清單之間
- 在一元運算子與其運算元之間
- 在空的引數清單中
- 在標籤與冒號之間
- 範圍運算子周圍::
成員初始化運算式清單和包含多個類別的基類清單應該在不同的行上撰寫。 這可讓您輕鬆地找出錯誤。
namespace Microsoft { namespace MSR { namespace CNTK {
Matrix ImplodeSelf(int x);
int ConfuseUs(float y);
class MainPart:
public Head,
protected Heart
{
public:
MainPart():
m_weight(99),
m_height(180)
{}
private:
void EatMore();
int m_consume, m_repeater;
};
template <typename Box>
void Inspect(Box & container)
{
switch (container)
{
case 1:
PrepareIt();
break;
case 2:
Finish();
break;
default:
break;
}
for (int i = 0; i < 30; ++i)
{
container << EatMore();
}
return container;
}
} } }
命名規範
- 類別和命名空間名稱使用 UpperCamelCase,也稱為 PascalCase。
- 所有大寫 (SQL、CNTK...) 中通常拼字的名稱都可以保留在所有大寫中。
- 全域和公用靜態函式、堆疊變數和類別成員 (類別變數,) 使用 lowerCamelCase。
- 類別成員函式 (方法) 使用 UpperCamelCase。
- 宏和常數使用 UPPER_SNAKE_CASE。
- 屬於類型的範本參數使用 UpperCamelCase。
- 不允許類型前置詞、匈牙利文標記法等等。 如果您需要厘清 floatMatrix 和 normalizedDoubleMatrix,請使用有意義的尾碼。
名稱前置詞
m_
針對成員變數s_
適用于任何內容中的靜態變數g_
針對全域變數,應該盡可能避免 (盡可能避免)
變數名稱應該是名詞。 函式名稱應該是動詞,但 getter 除外,可以是名詞。 例如,稱為 position 的類別屬性會有 setter SetPosition () 和 getter Position () 。
檔案名慣例
C++ 檔案應該具有 .cpp 副檔名,而標頭檔應具有 .h 副檔名。 不允許使用空格和底線。 不建議在檔案名中使用數位。
#define GOOD_MACRO(x) x
void CallOut();
unsigned const g_theAnswer = 42;
class SolveAllProblems
{
public:
void DoWhatWeNeed();
static void SetBugsOff();
int m_countReasons;
protected:
void NeverWorking();
static void GetReason();
int internalCounter;
private:
void InternalNeeds();
static void ShowReason();
int m_countShows;
};
template <typename TypeParam, int numberOfReasons>
void CallGlobal(boost::array<TypeParam, numberOfReasons> const &array);
前置處理器
強烈建議不要使用預處理器進行條件式編譯,因為它會導致程式碼已死。 只有在無法使用時,才使用它,例如使用選擇性相依性時。 特殊案例是使用條件式編譯,根據允許的平臺排除整個檔案。
根據條件式編譯平臺特定程式碼的喜好設定,您應該將目標設為撰寫可攜式程式碼,無論平臺為何,都能運作相同。 使用 Boost 程式庫可協助許多方面。 如果您必須根據平臺使用不同的程式碼,請嘗試將它封裝在協助程式函式中,讓平臺之間的程式碼數量維持在最小值。