試著看了一下Google Style的C++編碼規範,先隨手寫了一個最簡單的程式來試試Cpplit。代碼如下
————————————
#include <iostream>
using namespace std;
int main() {
cout << “Hello World!” << endl;
return 0;
}
————————————
運行指令
————————————
g++ main.cpp -o main
./main
————————————
得到結果
————————————
Hello World!
————————————
運行Cpplint,得到的結果如下
————————————
main.cpp:0: No copyright message found. You should have a line: “Copyright [year] <Copyright Owner>” [legal/copyright] [5]
main.cpp:1: Streams are highly discouraged. [readability/streams] [3]
main.cpp:3: Do not use namespace using-directives. Use using-declarations instead. [build/namespaces] [5]
Done processing main.cpp
Total errors found: 3
————————————
第一條說我沒有著作權資訊,第二條沒看懂,第三條說的是不能用std全部空間,建議使用具體用到的函數。
仔細上網查了半天,終於弄懂了第二條是什麼意思。
——————————————
5.9. 流
Tip 只在記錄日誌時使用流.
定義: 流用來替代 printf() 和 scanf().
優點: 有了流, 在列印時不需要關心對象的類型. 不用擔心格式化字串與參數列表不匹配 (雖然在 gcc 中使用 printf 也不存在這個問題). 流的構造和解構函式會自動開啟和關閉對應的檔案.
缺點: 流使得 pread() 等功能函數很難執行. 如果不使用 printf 風格的格式化字串, 某些格式化操作 (尤其是常用的格式字串 %.*s) 用流處理效能是很低的. 流不支援字串操作符重新排序 (%1s), 而這一點對於軟體國際化很有用.
結論: 不要使用流, 除非是日誌介面需要. 使用 printf 之類的代替.
使用流還有很多利弊, 但代碼一致性勝過一切. 不要在代碼中使用流.
拓展討論:
對 這一條規則存在一些爭論, 這兒給出點深層次原因. 回想一下唯一性原則 (Only One Way): 我們希望在任何時候都只使用一種確定的 I/O 類型, 使代碼在所有 I/O 處都保持一致. 因此, 我們不希望使用者來決定是使用流還是 printf + read/write. 相反, 我們應該決定到底用哪一種方式. 把日誌作為特例是因為日誌是一個非常獨特的應用, 還有一些是曆史原因.
流的支援者們主張流是不二之選, 但觀點並不是那麼清晰有力. 他們指出的流的每個優勢也都是其劣勢. 流最大的優勢是在輸出時不需要關心列印對象的類型. 這是一個亮點. 同時, 也是一個不足: 你很容易用錯類型, 而編譯器不會警示. 使用流時容易造成的這類錯誤:
cout << this; // Prints the address
cout << *this; // Prints the contents
由於 << 被重載, 編譯器不會報錯. 就因為這一點我們反對使用操作符重載.
有人說 printf 的格式化醜陋不堪, 易讀性差, 但流也好不到哪兒去. 看看下面兩段代碼吧, 實現相同的功能, 哪個更清晰?
cerr << “Error connecting to ‘” << foo->bar()->hostname.first
<< “:” << foo->bar()->hostname.second << “: ” << strerror(errno);
fprintf(stderr, “Error connecting to ‘%s:%u: %s”,
foo->bar()->hostname.first, foo->bar()->hostname.second,
strerror(errno));
你可能會說, “把流封裝一下就會比較好了”, 這兒可以, 其他地方呢? 而且不要忘了, 我們的目標是使語言更緊湊, 而不是添加一些別人需要學習的新裝備.
每一種方式都是各有利弊, “沒有最好, 只有更適合”. 簡單性原則告誡我們必須從中選擇其一, 最後大多數決定採用 printf + read/write.
——————————————
最終改好的程式如下,Cpplint能通過,g++也能通過
——————————————
// Copyright 2011 Bill_Lang
#include <cstdio>
int main() {
printf(“Hello World!”);
return 0;
}
——————————————
直接看Google Style會一會兒就煩了,但是配合著使用Cpplint,還是挺有樂趣的。看來還能協助自己提高C++編程的實際水平。
推薦朋友們也玩玩這個。
from:http://billlangjun.wordpress.com/2011/03/31/
========================================================================
寫代碼時必須注重代碼規範。養成良好的程式風格有助於提高代碼的可維護性與可閱讀性。
Google推出了自己的《Google C++ 風格指南》,在這份指南中各種C++編程中遇到的風格問題都得到了規範。由於原版篇幅過長,我在這裡整理一份簡化版的編程規範,以供各位參考。同時希望每一位狂想曲創作群組成員都能夠用此代碼規範編程。
注意:此份資料僅僅是Google推薦的代碼風格,不代表所有程式都要用此套規範編寫,當然我們還是強烈建議在建立任何項目或是工程之前,都應該統一風格,以便日後維護。
此套代碼規範與常用的一些規範(如匈牙利命名法等)可能有所出入,如果您是第一次使用,也許會感到些許不適應,但還請多多習慣此種編碼規範。
另:本文檔僅僅介紹的是C++編碼風格指南,而並非編程規範或是編程最佳化指南,如若想瞭解更多的代碼最佳化方法(如使用何種輸入輸出方式等)還請參考《effective C++》與《more effective C++》等著作。
好了,下面開始我們正式的風格規範探索。
一、標頭檔
1. 標頭檔寫在.h檔案中,實現檔案寫在.cc中而不是寫在.cpp中。
2. 每個.cc檔案都對應一個.h檔案,包含main()函數的檔案除外。
3. 每個標頭檔都要用#define保護,格式:
#ifndef FOO_BAR_BAZ_H_#define FOO_BAR_BAZ_H_…#endif // FOO_BAR_BAZ_H_
4. 只有當函數少於10行時才建議使用內嵌函式,內聯中包含迴圈或switch語句反而會降低效率。(Frankie註:不建議在內嵌函式中再調用其他函數)
5. 複雜的內嵌函式與函數模板建議放在-inl.h檔案中,並用#define保護。
6. 函數參數順序:先輸入參數,然後輸出參數。
7. #include路徑及順序:該.cc的.h標頭檔、C庫、C++庫、其他庫的.h檔案、本項目內的.h檔案。
二、範圍
1. 鼓勵在.cc檔案內使用匿名名字空間。不要在.h檔案中使用匿名空間。
2. 使用具名的名字空間時用名字把.h檔案及.cc檔案中除前置聲明外的源檔案全部封裝起來。
// .h 檔案namespace mynamespace {// 所有聲明都置於命名空間中// 注意不要使用縮排class MyClass { public: … void Foo();};} // namespace mynamespace// .cc 檔案namespace mynamespace {// 函數定義都置於命名空間中void MyClass::Foo() { …}} // namespace mynamespace
3. 最好不使用using namespace,而使用using ::foo::bar;類型。
4. 盡量不使用裸的全域函數,而要使用靜態成員函數或名字空間內的非成員函數。
5. 儘可能將變數至於最小範圍內,儘可能用初始化方式替代聲明再賦值,遇到for迴圈則要考慮效率問題(@July,代碼大全,深入理解電腦系統都有闡述)。如:
// 低效的實現for (int i = 0; i < 1000000; ++i) {Foo f; // 建構函式和解構函式分別調用 1000000 次!f.DoSomething(i);}
// 高效的實現Foo f; // 建構函式和解構函式只調用 1 次for (int i = 0; i < 1000000; ++i) { f.DoSomething(i);}
6. 禁止使用class類型的靜態或全域變數,包括STL容器,尤其是在多線程中。
三、類
1. 建構函式只初始化那些沒什麼意義的(trivial)資料,有意義的(non-trivial)資料建議使用Init()函數。
2. 如果類定義了若干成員變數且無其他建構函式,則需要定義一個預設建構函式。
3. 僅當只有資料時使用struct,其他一概使用class。
四、其他C++特性
1. 輸入參數是值參或const引用,輸出參數為指標。輸入參數可以為const指標,但決不能為非const的引用參數。
2. 僅在輸入參數類型不同但功能相同時使用重載函數,不要用函數重載去類比預設函數參數。
3. 不允許使用預設函數參數。
4. 不使用異常。(Frankie註:我的理解是這是因為Google自身代碼的健壯性造成的。Google認為使用異常並不能提高效率)
5. 禁止使用RTTI。
6. 使用C++類型轉換,如static_cast<>()而不是不要使用 int y = (int)x或 int y = int(x) 等轉換方式。
7. 不要使用流而要使用printf()與scanf()(@July,盡量,但不盲從)。記錄日誌除外。
8. 盡量使用前置自增自減,尤其是對迭代器和模板類型。
9. 儘可能使用const。
10. 使用斷言來指出變數為非負數,而不是使用無符號整型。
11. 整數用 0, 實數用 0.0, 指標用 NULL, 字元 (串) 用 '\0'。
12. 儘可能用 sizeof(varname) 代替 sizeof(type)。
13. 只是用Boost中被認可的庫。
五、命名規定
1. 儘可能給出描述性的名稱,如:int num_errors; int num_completed_connections;
2. 函數名通常是指令性的,如OpenFile(), set_num_errors()。
3. 檔案名稱要全部小寫,可以包含底線或連字號。(Frankie註:《狂想曲》統一使用底線)
4. 類型名稱的每個單詞首字母均大寫且不含底線:MyExcitingClass, MyExcitingEnum。
5. 變數命名一律小寫,單詞之間以底線串連。類成員變數以底線結尾。如:
my_exciting_local_variable
my_exciting_member_variable_
6. 結構體變數的資料成員命名與普通變數一樣。
7. 常量命名在名稱前加k:kDaysInAWeek。
8. 常規函數每個單字首大寫,沒有底線。
9. get和set函數要與存取的變數名匹配。如:
class MyClass { public: ... int num_entries() const { return num_entries_; } void set_num_entries(int num_entries) { num_entries_ = num_entries; } private: int num_entries_;};
10. 名字空間用小寫字母命名,用底線串連單詞。
11. 枚舉的命名與常量或宏一致:kEnumName或ENUM_NAME,並且建議使用前者,即常量風格的命名方式。
12. 宏命名全部大寫,單詞之間用底線串連。(Frankie註:#define保護檔案要用底線結尾)
六、注釋(Frankie註:此處為本人根據實際結合Google代碼規範提出的注釋方法,適用於《狂想曲》)
1. 使用。
2. 在每個檔案頭加入著作權公告,註明作者、修改日期、版本號碼等資訊(只要是我們內部人員,就只標明作者)。
3. 函數或者變數等的注釋沒有太多要求,只需注意對齊,內容詳盡即可。
4. 對尚未完成或者需要改進的代碼使用TODO注釋。如:
// TODO(kl@gmail.com) Use a "*" here for concatenation operator.// TODO(Zeke) change this to use relations.
TODO需要大寫,括弧內是您的名字,後接修改的方案等,是為了在“將來某一天做某事”,可以加上明確的時間或明確的事項。
七、格式(Frankie註:格式內容涉及面較廣,詳細請參見Google代碼風格指南來源文件)
1. 每行代碼字元數不超過80。
2. 用UTF-8編碼。
3. 只是用空格不適用製表位,每次縮排2個空格。
4. 傳回型別和函數名在同一行,參數盡量放在同一行。
5. if, else, switch等語句一定要使用大括弧{}。
from:http://tctop.wikispaces.com/Google%E4%BB%A3%E7%A0%81%E9%A3%8E%E6%A0%BC%E6%8C%87%E5%8D%97%E6%95%B4%E7%90%86