2015年7月22日水曜日

C/C++ のプログラムの書き方入門 コーディングルールはどこから学ぶ?(2016/3/15 追記)

読みやすいコードを書くことは重要。個人で書いていてもデバックのやり易さが違うし、チームだといわずもがな。下手なコードを書いていると、解りやすくかけ!!と言いたくなる。過去にそれですべて書き直しをしたことがなんどかありますね。っと、いっても私も長いこと書いてなくて忘れて下手なコード屋になっていますが。
ちょっと復習がてらに、私の知っているコーディングルールは、本のやつと自動車業界とNASA。各々紹介していきます。ってか引用のみです。
追記:
流石はGoogleさん。自分のコーディングルールを公開しているようでした。結構細かくて面白いので追記します。

目次
1.本
2.MISRA-C(自動車業界の標準です)
3.NASA
4.Google

本文
1.本から
1.1

プログラマと名乗っている人で知らないと、潜りだと思います。まぁ、俺は現在潜りなので持ってないけど。きれいに書くなら必読書。原書が英語なので、どこかで手に入るでしょう。

1.2.
最近知った本。ちょっと読んでみたらかなり良かったです。
英語版であるが、原初のサンプルがここでみることができる(The Art of Readable Code)

2.自動車業界:
MISRA-C
MISRA-C:2004(ちょっと古い) R:必要,A:推奨
環境
1.1 Rすべてのコードは、ISO/IEC 9899:1990,Program language-Cを満たしていなければならない。
1.2 R未定義または未規定の動作に依存してはならない。
1.3 R言語/コンパイラ/アセンブラが準拠するオブジェクトコードの共通インターフェース規格が定義されている場合に限り、複数のコンパイラや言語を用いることができる。
1.4 Rコンパイラやリンカが、外部識別子に対する31文字特徴及び大文字・小文字の区別をサポートしているかを確認しなければいけない。
1.5 A浮動小数点の実装は、定義された浮動小数点規格に従うべきである。
言語拡張
2.1 Rアセンブル言語が、カプセル化して分離しなければならない。
2.2 Rソースコードでは、/* ・・・ */ スタイルのコメントだけを用いなければならない。
2.3 R文字列 /* をコメント内で用いてはならない。
2.4 Aコードの一部を”コメントアウト”すべきではない。
文書化
3.1 R用いる処理系定義の動作は、すべて文書化しなければならない。
3.2 R文字集合及びそれに対応するエンコーディングは、文書化しなければならない。
3.3 A選定したコンパイラの整数除算の実装について確認し、文書化し、十分に配慮すべきである。
3.4 R用いる #pragma 指令は、すべて文書化し、説明しなければならない。
3.5 Rビットフィールドの処理系定義の動作とパッキングに(プログラムが)依存している場合、それは文書化しなければならない。
3.6 R製品コードで用いられるすべてのライブラリは、この文書の規定にしたがって記述されていなければならず、適切な妥当性確認を受けていなければならない.
文字集合
4.1 RISO/IEC 9899:1990で定義されている拡張表記だけを用いなければならない。
4.2 R3文字表記は、用いてはならない。
識別子
5.1 R(内部及び外部)識別子は、31文字を超える特徴に依存してはならない。
5.2 R外部スコープの識別子が隠蔽されることになるため、内部スコープの識別子には外部スコープの識別子と同じ名前を用いてはならない。
5.3 Rtypedef 名は、固有の識別子でなければならない。
5.4 Rタグ名は、固有の識別子でなければならない。
5.5 A静的記憶域期間をもつオブジェクトや関数の識別子は、再使用すべきではない。
5.6 A構造体及び共用体のメンバ名を除いて、あるネームスペースの識別子を、他のネームスペースの識別子と同じ綴りにしてはいけない。
5.7 A識別子は、再使用すべきではない。
6.1 R単なるchar型は、文字データの格納及び使用に限って用いなければならない。
6.2 Rsigned char型及びunsigned char型は、通知データの格納及び使用に限って用いなければならない。
6.3 A基本型の代わりに、サイズ及び符号属性(signedness)を示す typedef を用いなければならない。
6.4 Rビットフィールドは、unsigned int型またはsigned int型だけで定義しなければならない。
6.5 Rsigned int型のビットフィールドの幅は、2ビット長以上でなければならない。
定数
7.1 R(0以外の)8進定数及び8進拡張表記は、用いてはならない。
宣言及び定義
8.1 R関数は、常にプロトタイプ宣言をもち、プロトタイプ宣言は、関数定義及び関数呼び出しの両方から参照されなくてはならない
8.2 Rオブジェクト又は関数を宣言又は定義するときは、常にその型を明記しなければならない。
8.3 Rそれぞれの関数宣言及び定義で与えられる仮引数の型は、一致しなければならず。、戻り値の型も一致しなければならない。
8.4 Rオブジェクト又は関数を複数回宣言する場合、それらの型に互換性がなければならない。
8.5 Rヘッダファイル内で、オブジェクト又は関数を定義してはならない。
8.6 R関数は、ファイルスコープで宣言しなければならない。
8.7 Rオブジェクトが単一の関数内だけでアクセスされている場合は、そのオブジェクトをブロックスコープで定義しなければならない。
8.8 R外部オブジェクト又は外部関数は、単一のファイル内だけで宣言しなければならない。
8.9 R外部結合をもつ識別子は、唯一の外部定義をもたなければならない。
8.10 R外部結合が必要な場合を除き、ファイルスコープに存在するオブジェクト又は関数すべての宣言及び定義は、内部結合にしなければならない。
8.11 Rstatic記憶クラス指定子は、内部結合をもつオブジェクト並びに関数の定義及び宣言に対して用いなければならない。
8.12 R外部結合をもつ配列を宣言するときは、明示的にサイズを記述するか、初期化によって暗黙的にサイズを定義しなければならない。
初期化
9.1 Rすべての自動変数は、用いる前に値を代入しなければならない。
9.2 R配列及び構造体を0以外で初期化する場合は、構造を示し、それに合わせるために波括弧 "{ }" を用いなければならない。
9.3 Rすべての要素を明示的に初期化する場合を除き、列挙子リストでは、先頭以外のメンバを明示的に初期化するために、"=" 構文を用いてはならない。
算術型変換
10.1 R次の条件に該当する場合、整数型の値を異なる潜在型に暗黙的に変換してはならない。
a)同じ符号属性(signedness)をもつより大きな整数型への変換でない場合
b)式が複合式である場合
c)式が定数でなく、関数の実引数である場合
d)式が定数でなく、return式である場合
10.2 R次の条件に該当する場合、浮動小数点型の式の値を異なる型に暗黙的に変換してはならない。
a)より大きな浮動小数点型への変換でない場合
b)式が複合式である場合
c)式が関数の実引数である場合 
d)式がrturn式である場合
10.3 R整数型の複合式の値は、式の潜在型と同じ符号属性(signedness)をもつ、より小さな型へのキャストだけが許される。
10.4 R浮動小数点型複合式は、より小さな型へのキャストだけが許される。
10.5 Rビット単位の演算子 ~ 及び << が、潜在型の unsigned char 又は unsigned shortであるオペランドに適用される場合、その結果は、そのオペランドの潜在型へ直ちにキャストさせる。
10.6 Rすべての符号なし型の定数には、接尾語 "U" を付けなければならない。
ポインタの変換
11.1 R関数ポインタは、汎整数型以外の任意の型との間で変換してはならない。
11.2 Rオブジェクトポインタは、汎整数型、オブジェクト型を指す他のポインタ、voidポインタを除く任意の型との間で変換してはならない。
11.3 Aポインタ型と汎整数型との間でキャストすべきではない。
11.4 Aオブジェクト型を指すポインタとオブジェクト型を指す異なるポインタとの間でキャストすべきではない。
11.5 Rポインタで指し示された型からconst修飾やvolatiles修飾を取り除くキャストを行ってはならない。
12.1 A式中におけるC言語の演算子優先順位規則への依存は、極力制限すべきである。
12.2 R式の値は、規格が認められるどのような順序で評価されようとも、同じでなければならない。
12.3 Rsizeof演算子は、副作用がある式に用いてはならない。
12.4 R論理演算子 && 又は||の右側のオペランドには、副作用があってはならない。
12.5 R論理演算子 && 又は||のオペランドには、一次式なければならない。
12.6 A論理演算子(&&,||,!) のオペランドは、実質的なブール型になるべきである。実質的なブール型である式は、(&&,||,!) 以外の演算子のオペランドとして用いるべきではない。
12.7 Rビット単位の演算子は、潜在型が符号付きのオペランドに対して適用してはならない。
12.8 Rシフト演算子の右側のオペランドの値は、0以上、かつ、左側のオペランドの潜在型のビット幅未満でなければならない。
12.9 R単項マイナス(ー)演算子を、潜在型が符号なしの式に用いてはならない。
12.10 Rカンマ演算子は、用いてはならない。
12.11 A符号なし整数定数式の評価では、ラップアラウンドが発生しないようにすべきである。
12.12 R浮動小数点お潜在的なビット表現は、用いてはならない。
12.13 Aインクリメント(++)演算子及びデクリメント(ーー)演算子は、式中で他の演算子と混在させるべきではない。
制御文の式
13.1 Rブール値が生成される式の中で代入演算を用いてはならない。
13.2 Aオペランドが実質的なブール型である場合を除き、0との比較テストは明示的に行うべきである。
13.3 R浮動小数点式は、等価又は非等価のテストをしてはならない。
13.4 Rfor文の制御式は、浮動小数点型のオブジェクトを含んではならない。
13.5 Rfor文の3つの式には、ループ制御に関わるものだけを記述しなければならない。
13.6 Rforループの中で繰返しカウンタとして用いる数値変数は、ループの本体内で変更してはならない。
13.7 R結果が不変になるブール演算は、許されない。
制御フロー
14.1 R到達しないコードがあってはならない。
14.2 R空文でない場合には、次のいずれかの条件を満たさなければならない。
a)実行方法にかかわらず、1つ以上の副作用があること
b)制御フローを変更すること
14.3 R前処理の前の状態で、空文は、それ自身(;)を1行におかなければならない。ただし、空文のあとの最初の文字が、空白類文字であるという条件が満たされれば、空文の後にコメントを入れることができる。
14.4 Rgoto文を用いてはならない。
14.5 Rcontinue文を用いてはならない。
14.6 R繰返し文では、ループを終了させるためのbreak文の使用を最大でも1つだけに留めなければならない。
14.7 R関数では、関数の最後に唯一の出口がなくてはならない。
14.8 Rswitch, while, do ... while, for 文の本体を構成する文は、複合文でなければならない。
14.9 R"if(式)"構造の後には、複合文を続けなければならない。elseキーワードの後には、複合文又は他のif文を続けなければならない。
14.10 Rすべての if ... else if 構造は、else節で終了しなければならない。
switch文
15.1 Rswitchラベルは、それを直接う内包している複合分が、switch文の本体である場合にだけ用いなければならない。
15.2 R空でないswitch節は、無条件break文で終了しなければならない。
15.3 Rswitch文の最後の節は、default節でなければならない。
15.4 Rswitch式では、実質的なブール型になる値を用いてはならない。
15.5 Rすべてのswitch文には、最低でも1つのcase節を記述しなければならない。
関数
16.1 R可変個引数をもつ関数を定義してはならない。
16.2 R関数は、直接的か間接的かにかかわらず、その関数自身を呼び出してはならない。
16.3 R関数プロトタイプ宣言では、すべての仮引数に対して識別子を指定しなければならない。
16.4 R関数の宣言とその定義で用いられる識別子とは一致しなければならない。
16.5 R仮引数をもたない関数は、仮引数をvoid型で宣言しなければならない。
16.6 R関数に渡される実引数の数は、仮引数の数と一致しなければならない。
16.7 A関数プロトタイプ内のポインタ仮引数は、指し示しているオブジェクトを変更する目的でポインタが用いられていない場合、constへのポインタとして宣言すべきである。
16.8 R戻り値の方が非voidの関数の場合、すべての出口で、式をもつ明示的なreturn文を記述しなければならない。
16.9 R関数識別子には、前に&を付けるか、括弧付きの仮引数リスト(空でも可)を指定して用いなければならない。
16.10 R関数がエラー情報を戻す場合、エラー情報をテストしなければならない。
ポインタ及び配列
17.1 Rポインタ算術は、配列又は配列要素を扱うポインタにだけに適用しなければならない。
17.2 Rポインタ減算は、同じ配列の要素を扱うポインタにだけに適用しなければならない。
17.3 R>,>=, <, <= は、同じ配列を扱う場合を除き、ポインタ型に適用してはならない。
17.4 Rポインタ算術で許される形式は、配列添字付けだけでなければならない。
17.5 Aオブジェクトの宣言では、3段階以上のポインタ間接参照を記述すべきではない。
17.6 R自動記憶域にあるオブジェクトのアドレスを、そのオブジェクトの存在が終了した後にまで持続期間をもつ他のオブジェクトに代入してはならない。
構造体及び共用体
18.1 Rすべての構造体及び共用体の型は、コンパイル単位の最後に完全でなくてはならない。
18.2 Rオブジェクトを、重複するオブジェクトに代入してはならない。
18.3 Rメモリ領域は、無関係な目的で再使用してはならない。
18.4 R共用体は、用いてはならない。
前処理指令
19.1 Aファイル内で、#include 文の前には、他の前処理指令又はコメントだけを記述すべきである。
19.2 A#include指令のヘッダファイル名には、非標準文字を記述すべきではない。
19.3 R#include指令の後には、<filename>又は"filename"が続かなければならない。
19.4 RCマクロは、波括弧で囲まれた初期化子、定数、括弧で囲まれた式、型修飾子、記憶域クラス指定子、do-while-zero構造だけに展開されなければならない。
19.5 Rマクロは、ブロック内で#define又は#undefしてはならない。
19.6 R#undefを用いてはならない。
19.7 A関数形式マクロよりも関数を用いるべきである。
19.8 R実引数のすべてを指定せずに、関数形式マクロを”呼出し”してはならない。
19.9 R関数形式マクロの引数には、前処理指令のような字句を記述してはならない。
19.10 R#又は##のオペランドとして用いられている場合を除き、関数形式マクロの定義では、仮引数のそれぞれのインスタンスを括弧で囲まなければならない。
19.11 R前処理指令のすべてのマクロ識別子は、用いる前に定義しなければならない。ただし、#ifdef及び#ifndef前処理指令やdefined()演算子の場合には、その限りでない。
19.12 R1つのマクロ定義内で、#又は##前処理演算子を複数回用いてはならない。
19.13 A前処理演算子#及び##を用いてはならない。
19.14 Rdefined前処理演算子は、2つの標準形式のうち、いずれかの形式を用いなければならない。
19.15 R同じヘッダファイルの内容が2回取り込まれないように、予防措置を取らなければならない。
19.16 R前処理指令は、前処理で除外されたとしても、構文的に意味をもつようにしなければならない。
19.17 Rすべての#else, #elif, #endif前処理指令は、それに関連する#if指令又は#ifdef指令と同じファイルに存在しなくてはならない。
標準ライブラリ
20.1 R予約済み識別子及び標準ライブラリのマクロや関数は、定義、再定義又は定義の解消をしてはならない。
20.2 R標準ライブラリのマクロ、オブジェクト、関数の名前は、再使用してはならない。
20.3 Rライブラリ関数に渡される値については、その妥当性をチェックしなければならない。
20.4 R動的ヒープメモリ割り当ては、用いてはならない。
20.5 Rエラー指示子 errno は、用いてはならない。
20.6 R<stddef.h>ライブラリのoffsetofマクロは、用いてはならない。
20.7 Rsetjmpマクロ及びlongjmp関数は、用いてはならない。
20.8 R<signal.h>のシグナル処理機能は、用いてはならない。
20.9 R入出ライブラリ<stdio.h>は、製品コードで用いてはならない。
20.10 R<stdlib.h>ライブラリのライブラリ関数 atof, atoi, atolは、用いてはならない。
20.11 R<stdlib.h>ライブラリのライブラリ関数 abort, exit, getenv, systemは、用いてはならない。
20.12 R<time.h>ライブラリの時間処理関数は、用いてはならない。
実行時誤り
21.1 R実行誤りが最小であることを、次の内少なくとも1つ用いて保証しなければならない。
(a)静的解析ツール/技法
(b)動的解析ツール/技法
(c)実行時誤りをチェックするための明示的なコーディング

3.NASA(原文コピー)
10個でいいらしいです。

概要Wiki

  • Avoid complex flow constructs, such as goto and recursion.
  • All loops must have fixed bounds. This prevents runaway code.
  • Avoid heap memory allocation.
  • Restrict functions to a single printed page.
  • Use a minimum of two runtime assertions per function.
  • Restrict the scope of data to the smallest possible.
  • Check the return value of all non-void functions, or cast to void to indicate the return value is useless.
  • Use the preprocessor sparingly.
  • Limit pointer use to a single dereference, and do not use function pointers.
  • Compile with all possible warnings active; all warnings should then be addressed before release of the software.

  • 詳細な原文

    4.Google C++ Style Guide
    長いので、下のURLを参照ください。
    https://google.github.io/styleguide/cppguide.html

    0 件のコメント:

    コメントを投稿