規約というより初心者ガイドみたいなものです。コーディング上の注意事項を含みます。コーディングスタイルについてはこちら。
コーディング規約
- つぎの識別子プレフィックスは厳守事項
- クラス:C
- クラスメンバ変数:m_
- 変数、関数の型宣言は必ず行う。デフォルトでintになることは最新のC++言語規格では仮定されていません。
- for()内で宣言された変数のスコープはforブロックの外である。現在のC++言語規格ではforブロック内ですが、VC++6.0互換のため電八ソースはブロック内にするとコンパイル出来ません。VC++8.0以降はデフォルトがforプロック内になっていますので、注意が必要です。
- 論理演算子をビット演算子で代用しない。
- 処理系定義型 WORD、DWORD、LONG、LPCTSTR、HRESULT などを組み込み型で代用しない。
- intやlongなどの組み込み整数型にポインタを代入しない。ポインタを入れる整数型が必要な場合はINT_PTR、LONG_PTRなどのポインタ精度数値型を使用すること。WindowsAPIの戻り値や引数がこれら~_PTRで宣言されていたら厳密に従ってください。
- テンプレートの使用:現在は使用されていませんが、禁止しているわけではありません。
- STLの使用:現在は使用されていませんが、禁止しているわけではありません。
- 註:VC++6.0のSPにはSTLのバグ修正が含まれていません。 Fixes for Library Bugs in VC++ V5.0/V6.0 のパッチを当てましょう。
推奨事項
- 処理系定義型である
DWORD
、TCHAR
、CSTR
、LPCSTR
などを組み込み型よりも優先して使う。 - 文字配列 char[] より
CString
を優先して使う。場合により std::string を使う。 - 次の変数名のプレフィックスは推奨事項
- ポインタ:p
- 数値:n
- 論理型:b
- 文字列:s
- 整数型の評価は常に比較を行う。
- 0以外が真になることは誰でも知っていますが、
int x のとき、if (x) が if (
を意図しているのかどうかを判断するには余分な情報を必要とします。x != 0)
- 0以外が真になることは誰でも知っていますが、
- 整数型を論理型へ代入しない。
- 比較結果を代入するか、キャストしましょう。とくにBOOLにintを代入しているのを見たら普通はコーディングミスだと思うでしょう。
- 論理型が欲しい場合はboolを使用する。
- 歴史的な経緯でBOOLが定義され、今でもBOOLはboolのエイリアスではありません。現在はプロパーなbool型というものがあるのですから、BOOLよりboolを使いましょう。
- BOOLは論理型(bool)だと考える。
- BOOLは凡そ、論理値として評価すれば真/偽となり、intとして扱えば1/0である様に期待されます。少なくとも自分の書くコードでその期待を裏切らないようにしましょう。
- WindowsAPIの中に戻り値がBOOLで宣言されているにもかかわらず、TRUE / FALSE 以外を返すものがあります(
cf. GetMessage()
)が、そういう場合は戻り値をBOOL型で受け取らないようにしましょう。(GetMessage()
の宣言をintに直してくれないかな。)
- 論理型の真偽評価は比較を使用しない。
bool
は比較しなくてもtrue
かfalse
に決まっています。BOOL
型をTRUE
と比較するのは広く言われているとおり絶対に行うべきではありません。TRUE
(=1)以外でも真だからです。FALSE
との比較なら安全ですが、そもそも比較しなければこの様な心配も無いのです。- 同じ理由で
BOOL
型同志の比較も駄目です。1以外が入っているかも知れないからです。(前述の通り意図して入れるのは止めましょう)
- ポインタのNULLチェックはNULLと比較する。
- NULL ポインタは偽になる事は誰でも知っていますが数値と同じく論理型でないものは比較をしよう。
- 代入式を評価しないで、代入後の変数を評価する。
- 例外も稀にあります。
- ローカル変数はなるべく使用する直前に宣言する。
- 関数先頭でしか宣言できなかったC89のことは忘れましょう。変数のスコープはなるべく狭い方が良いです。
- 引数、変数、戻り値、メンバ関数のconst修飾が必要でないか常に考慮する。
- 参照・ポインタがconstかどうかはとても重要です。
- 引数は単なるローカル変数です。
- 関数内部で引数を変更しても別に構いません。変更してはいけないものならconst修飾しましょう。
- 引数を参照・ポインタにするかどうか常に考慮する。
- 関数内部でコピーするくらいなら引数で値を受け取ればコピーされてきますよ?
- 関数の戻り値を値で返すか参照で返すか。
- RVOというものがあるので一時オブジェクトを返しても効率は悪化しません。
- switchのcaseラベルフォールスルーは濫用しない。
- switchのdefaultラベルを必ず付ける。
- defaultにならないはずであれば、そこにはログ出力やASSERT()等のエラー時処理を書くことがdefault付ける理由になります。
- switchのdefaultラベルはなるべく最後に置く。
- なるべくです。他のcaseラベルと同じ処理をコピーしてまで最後に置いたりしなくてよいです。
- for()の括弧内でループ制御に関係のない処理をしない。
- ループで行いたい処理は
{...}
内に書きましょう。
- ループで行いたい処理は
- 評価順序を明確にする()は積極的に付ける。
- 三項演算子の条件式が演算式の場合は()で囲む。
- 比較演算子は
>, >=
よりも<, <=
を優先して使用する。- 今更、定数を常に左辺に書くのは可読性を落すだけでメリットはありませんが、
if ((0 < x) || (x <= 100))
のような書き方はメリットがあります。
- 今更、定数を常に左辺に書くのは可読性を落すだけでメリットはありませんが、
- 変更に関してはコメントを残す。
以下のような形を採っています。(前例がたくさんありますのでソースを参照してください)
- 元のコードをコメントとして残す。
- 関数ヘッダコメントに変更内容を詳しく書く。(まるごと置き換えたような大きな変更の場合推奨)
- 変更行にコメントを書く。(小さな変更の場合簡単推奨)
- 関数化した、ファイル分割したなど大きな単位で移動した場合は、元コードを削除して移動元に移動先のコメントを付ける。
- 環境によって存在しないDLLを使用する場合はLoadLibrary()して使用する。(旧環境での動作を確保するため。den8.cppに前例があるので、参照してください。)
- Doxygen形式のコメントを付ける。細かいフォーマットはコメントを参照してください。
- その他のコメント
- ソースの解説は必要なだけ付けてください。関数、クラスの解説はDoxygenコメントを使用してください。
- パッチを統合したときパッチ番号をコメントとして入れているのでご自分の開発中の利便性意外で日付等を入れる必要はありません。もし入っていても削除しません。
- フラグは肯定形で作る
- フラグやオプションスイッチは
true
のときそれが有効になるように作るべきです。trueにすると無効になるスイッチは間違いやすいです。大抵の場合、表現を反転するだけで改善できます。
例えば、「サーバーから削除しない」ではなく、「サーバーに残す」にするべきです。
- フラグやオプションスイッチは