トップ 履歴 一覧 カテゴリ ソース 検索 ヘルプ RSS ログイン

Data/CCoding

INDEX

昔書いた「C言語 コーディング標準」より

1. はじめに

本文書は、C言語のコーディングの規約について記述したものである。基本的には、ANSI C に準じたソース記述とする。

2. 表記基準

 2.1. 全般

  1. 1行120バイトまでを目処に記述する。長くなる場合は、適に折り返しインデントを行う。
  2. 1関数のステップ数は、200ステップまでを目処に記述する。
  3. リテラル値は、極力関数内では記述せず、定数定義(もしくは、列挙子定義)を利用する。
  4. コンパイル時に値が決まる定数は、defineを利用する。
  5. 環境や実行時によって値が変わる定数は、外部パラメータ化(起動引数、環境変数、設定ファイル等から取得)する。
  6. プロジェクトや複数ソースで共通のものは、個々に記述せずにヘッダファイルに記述し、インクルードする。

 2.2. 基本構成

2.2.1. ヘッダ部

開発するプロジェクト名、モジュール名、処理概要、及び、変更履歴を記述する。

/******************************************************************************/
/*                                                                            */
/*      [プロジェクト名]                                                      */
/*          株式会社ほげほげ商事  売上管理システム?                          */
/*                                                                            */
/*      [モジュール名]                                                        */
/*          売上管理 売上集計表作成(部課・得意先・商品別) ? (foofoo.c?)     */
/*                                                                            */
/*      [ 日  付 ]      作成日  '05/05/29?       Revision 2.00?             */
/*                      更新日  '05/06/29?                                   */
/*                                                                            */
/*      [処理概要]                                                            */
/*          売上実績ファイルを読み込み、各キー毎で数量、金額を集計し、  ?    */
/*          売上集計ファイルを作成する                                        */
/*                                                                            */
/******************************************************************************/
/*                                                                            */
/*      [ 履  歴 ]                                                            */
/*             日  付   |Revision|             内       容                    */
/*          ------------+--------+---------------------------------------     */
/*           2005/05/29 |  1.00  | リリース                             ?    */
/*           2005/06/01 |  1.01  | 特定の部課での集計が正しくないのを修正     */
/*           2005/06/29 |  2.00  | 各コードの名称取得処理追加                 */
/*                                                                            */
/******************************************************************************/

それぞれ、以下のように記述する。

  1. 開発プロジェクト名を記述する。
  2. モジュール名(処理名)を記述する。
  3. モジュールのファイル名を記述する。
  4. 作成日を記述する。
  5. 最終更新日を記述する。ソースを修正した際に日付を更新する。
  6. 現在のリビジョンを記述する。納品時のリビジョンが1.00となる。
  7. モジュールの処理概要を記述する。
  8. モジュールの更新履歴を記述する。リビジョンごとに修正した大まかな内容を記述する。

2.2.2. include文記述

システム及びユーザ定義のヘッダファイルを取り込むinclude文を記述する。

#include <stdio.h>
#include <ファイル名>
#include "ファイル名"
    :
  1. stdio.h等のシステムヘッダファイルは、「<>」でファイル名を囲む。
  2. プロジェクト共通や各自で作成したユーザ定義ヘッダファイルは、「""」でファイル名を囲む。
  3. プロジェクト共通、及び、他のソースでも使用するものは、各ソースで毎回記述するのではなく、ヘッダファイルに記述しインクルードする。

2.2.3. 定数定義

プログラム中に現れる定数または文に対して、意味のある定義名の設定を行い、マジックナンバーは極力使用しないようにする。

/*****************************************************************************/
/*   定数定義                                                                */
/*****************************************************************************/
#define FILE_NAME_SIZE      512                 /* ファイル名最大長 */
#define 定義名              文字列              /* コメント */
    :
  1. プロジェクト共通の定数は、ヘッダファイルに定義する。
  2. すでに定義されているものは、再定義は行わない。(#undefの使用は禁止する)

2.2.4. マクロ関数定義

プログラムで使用するマクロ関数を定義する。

/*****************************************************************************/
/*   マクロ関数定義                                                          */
/*****************************************************************************/
/* 閏年か判定マクロ関数 */
#define isLeapYear(nYear) \
        (((nYear%4)==0) && (((nYear%100)!=0) || ((nYear%400)==0)))
/* コメント */
#define マクロ関数名        処理ロジック
    :
  1. プロジェクト共通の定数は、ヘッダファイルに定義する。
  2. すでに定義されているものは、再定義は行わない。(#undefの使用は禁止する)
  3. 処理ロジックが長くなる場合は、改行の前に“\”を使い継続行として、インデントし数行に分け記述する。

2.2.5. 列挙子定義

列挙定数(整数定数)のリストの定義を行い、typedefを用いて、データ型を定義する。

/*****************************************************************************/
/*   列挙子定義                                                              */
/*****************************************************************************/
typedef enum _タグ名 {
    列挙定数1 = 1,    /* コメント */
    列挙定数2,        /* コメント */
       :
    列挙定数n         /* コメント */
} データ型名;
    :
  1. データ型名は、原則すべて大文字、単語の区切りにはアンダーバー(“_”)を使用する。
  2. タグ名は、アンダーバー+データ型を小文字にしたものを使用する。
  3. 定数値に決まった値がない場合、開始数値を指定し、0以外から始める。

2.2.6. 構造体 / 共用体定義

構造体、及び、共用体のデータ構造の定義を行い、typedefを用いて、データ型を定義する。

/*****************************************************************************/
/*   構造体/共用体定義                                                       */
/*****************************************************************************/
typedef struct _タグ名 {
    データ型    メンバー1;      /* コメント */
    データ型    メンバー2;      /* コメント */
       :
    データ型    メンバーn;      /* コメント */
} データ型名;
    :
  1. データ型名は、原則すべて大文字、単語の区切りにはアンダーバー(“_”)を使用する。
  2. タグ名は、アンダーバー+データ型を小文字にしたものを使用する。

2.2.7. グローバル変数宣言

グローバル変数 (関数・ブロック外で宣言される変数)を宣言する。

/*****************************************************************************/
/*   グローバル変数宣言                                                      */
/*****************************************************************************/
記憶クラス データ型 変数名;     /* コメント */
    :
  1. グローバル変数の使用は、極力避けること。
  2. 宣言したファイル内でしか使用しないものは、記憶クラスに“static”を指定する。
  3. 他で宣言された同名のグローバル変数を使用する場合は、記憶クラスに“extern”を指定する。
  4. プロジェクト共通のグローバル変数は、“extern”を指定した変数宣言をヘッダファイルに記述する。実体は、ライブラリ等のプロジェクト共通で使用されるものに宣言する。

2.2.8. 関数プロトタイプ宣言

ファイル内に記述した、関数のプロトタイプ宣言を行う。

/*****************************************************************************/
/*   関数プロトタイプ宣言                                                    */
/*****************************************************************************/
データ型 関数名(データ型 引数1, データ型 引数2, …);
    :
  1. ヘッダファイルに記述しないものは、すべてここでプロトタイプ宣言をする。
  2. 関数の記述と同じ様に仮引数も記述する。

2.2.9. 関数の記述

各関数の処理を記述する。

/*******************************************************************
     関数名称:barbar
     関数機能:処理概要
      引 数 :データ型     引数1       コメント
      戻り値 :正常終了=RC_OK、異常終了=RC_NG
*********************************************************************/
データ型 barbar(データ型 引数1, … ){
    データ型    変数名;     /* コメント */
    :
   処理
    :
    return( 戻り値 );
}
  1. 関数を記述して行く順番は、原則として、処理が行われる順番、階層の浅いものから記述して行く。
  2. 戻り値、および、引数がない場合は、“void”を指定し、明示的にする。
  3. 引数で、値を戻さない(変化させない)ポインタ変数には、「const char* string」の様に、constを指定する。

2.2.10. フッタ部

ファイルの内容が終わりであることを明記する。

/*****************************************************************************/
/*   End Of File   (foofoo.c)                                                */
/*****************************************************************************/
  1. コンパイラにより、エラーもしくはワーニングとなるので、最後に改行を必ず入れること。

2.2.11. ヘッダファイルの構成

  1. 基本は上記の基本構成と同じ。ただし、関数の記述は、禁止する。
  2. ヘッダファイルを複数箇所でインクルードしてもエラーにならないように、2重読込処置をする。
2重読込処理方法

下記の文をヘッダの直後に挿入し、

#ifndef _INCLUDE_COMN_H_
#define _INCLUDE_COMN_H_

下記の文をフッタ部の直前に挿入する。

#endif /* _INCLUDE_COMN_H_ */

「COMN」の部分は、ヘッダファイルのファイル名(.hは除く)を大文字にしたものに置き換える。

 2.3. 字下げ(インデント)

インデントは、スペース4文字で行う。スペースとタブの混在は、環境によってずれるので禁止する。

  1. 制御文の記述では、制御文の各ブロックのネストごとにインデントを行う。
  2. 関数の呼び出し、制御文の記述で、継続行の持つ場合は、2行目以降にインデントを入れる。
  3. 変数宣言の際、データ型と変数名の間にインデントを入れる。

 2.4. 空白と空行

  1. 関数内の変数宣言部と手続きの部の間には空行を入れる。
  2. 関数の手続き部で、ある処理の単位でまとまるように空行を入れる。
  3. 演算子の前後には空白を入れる。
  4. セミコロン、カンマの後に文が続く場合は、セミコロン、カンマの直後に空白を入れる。

 2.5. コメント

  1. コメントは、“/*”の後に、“*/”の前に空白を入れ、コメントを囲む。
  2. “//”で始まる行コメントは極力使用しない。
  3. コメントは、半角英数字、半角記号および全角日本語とし、半角カナは極力使用しない。
  4. 「if ( val == 0 /* && bar != 0 */ ) 」のように、文の中にコメントは記入しない。

 2.6. メイン関数

メイン関数は原則以下のように記述する。

/* *****************************************************************
     関数名称:メイン関数
     関数機能:処理の全体
      引 数 :起動パラメータ
      戻り値 :プロセス終了値
*******************************************************************/
int main(int argc,char *argv[]){
    int     iReturnCode;

    /* 前処理 */
    iReturnCode = ProcInit(argc, argv);

    /* 主処理 */
    if ( iReturnCode == RC_OK ) {
        iReturnCode = ProcMain( );
    }

    /* 後処理 */
    iReturnCode = ProcEnd(iReturnCode);

    return(iRetCode);
}
  1. 前処理では、プログラム実行時に必須の処理(ログの開始メッセージ、パラメータの取得、DB接続等)を行う。
  2. 主処理では、実際の処理を記述して行く。
  3. 後処理では、プログラム終了時に行う処理(ログの終了メッセージ、DB切断等)を行う。

3. 命名基準

 3.1. 変数名

  1. 一文字の変数名、意味のなさない変数名(aa, a1, a2等)は使用しない。

 3.2. 関数名

  1. 一文字の変数名、意味のなさない変数名(aa, a1, a2等)は使用しない。

 3.3. 定義名

  1. すべて大文字とし、単語間の区切りには、アンダーバー(“_”)を使用する。

4. 文法基準

 4.1. 式

4.1.1. 演算子の優先順位

C言語には多くの演算子が存在し、それぞれに明確な優先順位が存在する。しかし、複数の演算子を使用した場合、計算の順序が複雑となる。演算子の優先順位に頼らず、括弧を利用し計算順序がわかりやすくする。

4.1.2. インクリメント、デクリメント

インクリメント(++)演算子、デクリメント(--)演算子は、式の評価前(もしくは後)に加減算を行う。原則、単独で使用し、他の演算子と合わせて使用しない。1つの式で複数の演算子を使用したり、他の演算子と一緒に使用すると、複数の値が変化するので見づらくなる。

4.1.3. 配列

  1. 配列の添え字にマイナスは使用しない。
  2. 文字列をセットするchar型配列のサイズで、文字列長が決まる場合は、文字列長+NULL終端分(+1)のサイズ文のみ確保する。また、変数宣言時の要素数の指定は、「文字列長+1」の様に指定する。
  3. ループなどで配列の要素数を指定する場合は、直値で記述せず、sizeofを使用する。

 4.2. 制御文

4.2.1. if文

if文は、2分岐条件文で、式の評価の結果が、真か偽かで処理を分ける制御文である。

  1. “if”と“(”、 “)”と“{”のそれぞれの間には、半角空白を1文字入れる。
  2. 始まりのブレス(“{}”)は、if文と同じ行に置き、終わりのブレス(“{}”)は、if文と同じインデント位置にし1行単独で書く。
  3. 実行する文が1つしかない場合でも、必ずブレス(“{”,“}”)を使用し、ぶら下がり文は禁止する。ただし、“else if”は、例外とする。
  4. if文の式に、変数の値を変化させる インクリメント、デクリメント および、代入演算子(=,+=等) は使用しない。
  5. if文の式に、順次演算子(“,”)、条件演算子(“? :”) は使用しない。
  6. if文の式に、関数の記述は、戻り値を比較する場合を除いて禁止する。

4.2.2. switch文

switch文は、多分岐選択条件文で、式の評価し一致する定数式のcaseキーワードに制御を移す制御文である。

  1. “switch”と“(”、“)”と“{”のそれぞれの間には、半角空白を1文字入れる。
  2. “case”、定数式、“:” および “default”、“:”のそれぞれの間にも、半角空白を1文字入れる。
  3. 始まりのブレス(“{}”)は、switch文と同じ行に置き、終わりのブレス(“{}”)は、switch文と同じインデント位置にし1行単独で書く。
  4. case、defaultキーワードは、インデントを1つ下げ、それぞれの文は、更にインデントを1つ下げる。
  5. 1つのcaseキーワードには、1つの定数式しか記述できない。従って、複数の定数式で同一の処理を行う場合は、caseキーワードの行を並べて記述する。
  6. C言語のswitch文は、実行すべき文の選択ではなく、制御を移すべき場所の選択である。よって、breakを記述しないと、後続の文も実行されてしまう。そのため、2つ目以降のcaseおよびdefaultキーワードの前には、break文を入れる。意図的に後続の文も実行させるためにbreak文を記述しない場合は、その旨をコメントとして記述する。
  7. switch文の式に、変数の値を変化させる インクリメント、デクリメント および、代入演算子(=,+=等) は使用しない。
  8. switch文の式に、順次演算子(“,”)、条件演算子(“? :”) は使用しない。

4.2.3. while文

while文は、一定条件下での繰り返しを行う、繰り返し文である。

  1. “while”と“(”、“)”と“{”のそれぞれの間には、半角空白を1文字入れる。
  2. 始まりのブレス(“{}”)は、while文と同じ行に置き、終わりのブレス(“{}”)は、while文と同じインデント位置にし1行単独で書く。
  3. 実行する文が1つしかない場合でも、必ずブレス(“{”,“}”)を使用し、ぶら下がり文は禁止する。
  4. while文の式に、変数の値を変化させる インクリメント、デクリメント および、代入演算子(=,+=等) は、原則使用しない。
  5. while文の式に、順次演算子(“,”)、条件演算子(“? :”) は使用しない。
  6. while文の式に、関数の記述は、戻り値を比較する場合を除いて禁止する。

4.2.4. do-while文

while文と同様の繰り返し文である。ただ、while文と違い、先に文を実行しその後に式の評価が行われる。

do-while文は、使用しない。

4.2.5. for文

for文は規定の回数の繰り返しを行う、繰り返し文である。

  1. “for”、“(”、初期設定式、“;”、実行判定式、“;”、再設定式、“)”、“{” のそれぞれの間には、半角空白を1文字入れる。
  2. 始まりのブレス(“{}”)は、for文と同じ行に置き、終わりのブレス(“{}”)は、for文と同じインデント位置にし1行単独で書く。
  3. 実行する文が1つしかない場合でも、必ずブレス(“{”,“}”)を使用し、ぶら下がり文は禁止する。
  4. 初期設定式には、繰り返しの回数を制御するループ制御変数の初期化のみを行う。
  5. 実行判定式には、ループ制御変数の繰り返しの条件式のみを行う。
  6. 再設定式には、ループ制御変数の加減算のみを行う。
  7. for文の各式は、省略しない。省略する場合は、その旨をコメントとして残す。
  8. for文の各式に、順次演算子(“,”)、条件演算子(“? :”) は使用しない。
  9. for文の各式に、関数の記述は、使用しない。

4.2.6. break文とcontinue文

break文は、最も内側のswitch, while, do-while, for文を終了し、その制御を抜ける。continue文は、最も内側のwhile, do-while, for文の残りを実行せず、次の繰り返しを実行する。

  1. 繰り返し文からある条件下で抜ける場合は、switch文を使用せず、if文を使用する。switch文のブロック内にbreak文を記述しても、switch文を終了するだけで、ループを抜け出せないので注意が必要である。

4.2.7. return文

return文は、関数の実行を終了し、呼び出した関数に制御を移す文である。

  1. 同一関数内で複数のreturn文の記述は禁止とし、関数の最後に記述する。
  2. void型関数の場合、“return;”と記述する。
  3. void型関数以外の場合は、“return(式);”と記述する。式は、関数の型に合ったリテラル値 もしくは、変数にする。
  4. return文の中での演算は原則禁止とする。

4.2.8. goto文とラベル

ラベル及びgoto文の使用は原則禁止とする。

5. Pro*C

 5.1. 全般

  1. ソース内に記述するSQL文はすべて大文字で記述する。
  2. 項目名、別名等に、予約語、小文字、全角文字を使用する場合は、ダブルクォーテーションで囲む。
  3. SQL文が短く1行で書く場合は、「EXEC SQL 〜SQL文〜;」と記述する。
  4. SQL文が長く複数行で書く場合は、「EXEC SQL」と「;」は同じインデント位置で記述し、その間のSQL文は1つインデントを下げて間に記述する。
EXEC SQL EXECUTE IMMEDIATE :H_cSqlStmt;
EXEC SQL DECLARE CUR1 CURSOR FOR
    SELECT  EMPNO
       :
;
EXEC SQL OPEN CUR1;

 5.2. ホスト変数宣言

  1. ホスト変数は、すべてDECLARE SECTION内で宣言する。
  2. ホスト変数には、変数名のプレフィックスとして“H_”をつける。
  3. DBの項目と対になるホスト変数名は、項目名をそのまま使用する。
  4. ホスト変数のデータ型は、原則以下に従う。文字列のサイズは、必要分のみとする。
  5. インジケータ変数の変数名は、対になるホスト変数と同名とし、プレフィックスは、“H_”代わりに“I_”を付ける。
  6. 構造体を使用する場合には、メンバー名にはプレフィックスの“H_”は付けず変数名のみに付ける。
Oracleデータ型 Pro*Cデータ型 補足説明
CHAR(n) / VARCHAR(n) char[n+1] nバイトの文字列(+1は、NULL終端分)
 〃 varchar[n] nバイトのサイズ付き文字列
NUMBER / NUMBER(p) / NUMBER(p,s) long / double 整数の値かつlongの精度範囲内(32bitで9桁)の場合は、longを使用、それ以外は、doubleを使用
 〃 char[n+1] / varchar[n] nは必要桁数 + 符号分(+1) + 小数を含む場合の小数点分(+1)。但し、型変換をする場合は、それに従う。
DATE / TIMESTAMP char[n+1] / varchar[n] 型変換をすること
 〃 long / double 型変換をすること

 5.3. エラー処理

SQLを実行した際、エラーおよび警告が発生する。そのエラー処理の方法として、ProCは、SQLコミュニケーション領域(SQLCA)に持つ、SQLCODE(sqlca.sqlcode)による方法と、WHENEVER文を指定し、アクションを決める方法があります。

  1. WHENEVER文は使用せず、SQLCODEの値でエラー処理を行う。

 5.4. プリコンパイラオプション

ProCのオプションにはいくつがあります。以下は、指定する。但し、デフォルトで有効な場合は特に指定しなくてよい。

  1. 「LINE=YES」を指定し、Cソース内に「#line」を挿入させる。Cのコンパイルエラー時にProCのソースコードの行数で表示されるようになるため、修正しやすくなる。
  2. 「PARSE=NONE」を指定し、EXEC SQL以外の部分の構文解析をしないようにする。他の指定では、Cソースすべてが解析しようとする。そのため、行コメントが使えない。インクルードディレクトリをすべて指定する必要がある。などの制限が多くなる。
  3. 「MODE=ORACLE」を指定し、Oracleモードで動作するようにする。ANSIモードでは、カーソルオープンをしたまま、コミットが出来ない等制限が多い。
  4. 「SQLCHECK=SEMANTICS USERID=user/pass@tsn」を指定し、プリコンパイル時に項目名等のチェックも行うようにする。但し、接続するDBがない場合やテーブルがない場合、項目名にCASEが存在する等でSQL文があっているのにエラーになる場合は、「SQLCHECK=SYNTAX」を指定する。
  5. 「CHAR_MAP=CHARZ」を指定し、DBの値をchar型のホスト変数へセット方法を指定する。

最終更新時間:2008年11月14日 00時35分00秒 指摘や意見などあればSandBoxのBBSへ。