INDEX
昔書いた「C言語 コーディング標準」より
1. はじめに
本文書は、C言語のコーディングの規約について記述したものである。基本的には、ANSI C に準じたソース記述とする。
2. 表記基準
2.1. 全般
- 1行120バイトまでを目処に記述する。長くなる場合は、適に折り返しインデントを行う。
- 1関数のステップ数は、200ステップまでを目処に記述する。
- リテラル値は、極力関数内では記述せず、定数定義(もしくは、列挙子定義)を利用する。
- コンパイル時に値が決まる定数は、defineを利用する。
- 環境や実行時によって値が変わる定数は、外部パラメータ化(起動引数、環境変数、設定ファイル等から取得)する。
- プロジェクトや複数ソースで共通のものは、個々に記述せずにヘッダファイルに記述し、インクルードする。
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.00となる。
- モジュールの処理概要を記述する。
- モジュールの更新履歴を記述する。リビジョンごとに修正した大まかな内容を記述する。
2.2.2. include文記述
システム及びユーザ定義のヘッダファイルを取り込むinclude文を記述する。
#include <stdio.h> #include <ファイル名> #include "ファイル名" :
- stdio.h等のシステムヘッダファイルは、「<>」でファイル名を囲む。
- プロジェクト共通や各自で作成したユーザ定義ヘッダファイルは、「""」でファイル名を囲む。
- プロジェクト共通、及び、他のソースでも使用するものは、各ソースで毎回記述するのではなく、ヘッダファイルに記述しインクルードする。
2.2.3. 定数定義
プログラム中に現れる定数または文に対して、意味のある定義名の設定を行い、マジックナンバーは極力使用しないようにする。
/*****************************************************************************/ /* 定数定義 */ /*****************************************************************************/ #define FILE_NAME_SIZE 512 /* ファイル名最大長 */ #define 定義名 文字列 /* コメント */ :
- プロジェクト共通の定数は、ヘッダファイルに定義する。
- すでに定義されているものは、再定義は行わない。(#undefの使用は禁止する)
2.2.4. マクロ関数定義
プログラムで使用するマクロ関数を定義する。
/*****************************************************************************/
/* マクロ関数定義 */
/*****************************************************************************/
/* 閏年か判定マクロ関数 */
#define isLeapYear(nYear) \
(((nYear%4)==0) && (((nYear%100)!=0) || ((nYear%400)==0)))
/* コメント */
#define マクロ関数名 処理ロジック
:
- プロジェクト共通の定数は、ヘッダファイルに定義する。
- すでに定義されているものは、再定義は行わない。(#undefの使用は禁止する)
- 処理ロジックが長くなる場合は、改行の前に“\”を使い継続行として、インデントし数行に分け記述する。
2.2.5. 列挙子定義
列挙定数(整数定数)のリストの定義を行い、typedefを用いて、データ型を定義する。
/*****************************************************************************/
/* 列挙子定義 */
/*****************************************************************************/
typedef enum _タグ名 {
列挙定数1 = 1, /* コメント */
列挙定数2, /* コメント */
:
列挙定数n /* コメント */
} データ型名;
:
- データ型名は、原則すべて大文字、単語の区切りにはアンダーバー(“_”)を使用する。
- タグ名は、アンダーバー+データ型を小文字にしたものを使用する。
- 定数値に決まった値がない場合、開始数値を指定し、0以外から始める。
2.2.6. 構造体 / 共用体定義
構造体、及び、共用体のデータ構造の定義を行い、typedefを用いて、データ型を定義する。
/*****************************************************************************/
/* 構造体/共用体定義 */
/*****************************************************************************/
typedef struct _タグ名 {
データ型 メンバー1; /* コメント */
データ型 メンバー2; /* コメント */
:
データ型 メンバーn; /* コメント */
} データ型名;
:
- データ型名は、原則すべて大文字、単語の区切りにはアンダーバー(“_”)を使用する。
- タグ名は、アンダーバー+データ型を小文字にしたものを使用する。
2.2.7. グローバル変数宣言
グローバル変数 (関数・ブロック外で宣言される変数)を宣言する。
/*****************************************************************************/ /* グローバル変数宣言 */ /*****************************************************************************/ 記憶クラス データ型 変数名; /* コメント */ :
- グローバル変数の使用は、極力避けること。
- 宣言したファイル内でしか使用しないものは、記憶クラスに“static”を指定する。
- 他で宣言された同名のグローバル変数を使用する場合は、記憶クラスに“extern”を指定する。
- プロジェクト共通のグローバル変数は、“extern”を指定した変数宣言をヘッダファイルに記述する。実体は、ライブラリ等のプロジェクト共通で使用されるものに宣言する。
2.2.8. 関数プロトタイプ宣言
ファイル内に記述した、関数のプロトタイプ宣言を行う。
/*****************************************************************************/ /* 関数プロトタイプ宣言 */ /*****************************************************************************/ データ型 関数名(データ型 引数1, データ型 引数2, …); :
- ヘッダファイルに記述しないものは、すべてここでプロトタイプ宣言をする。
- 関数の記述と同じ様に仮引数も記述する。
2.2.9. 関数の記述
各関数の処理を記述する。
/*******************************************************************
関数名称:barbar
関数機能:処理概要
引 数 :データ型 引数1 コメント
戻り値 :正常終了=RC_OK、異常終了=RC_NG
*********************************************************************/
データ型 barbar(データ型 引数1, … ){
データ型 変数名; /* コメント */
:
処理
:
return( 戻り値 );
}
- 関数を記述して行く順番は、原則として、処理が行われる順番、階層の浅いものから記述して行く。
- 戻り値、および、引数がない場合は、“void”を指定し、明示的にする。
- 引数で、値を戻さない(変化させない)ポインタ変数には、「const char* string」の様に、constを指定する。
2.2.10. フッタ部
ファイルの内容が終わりであることを明記する。
/*****************************************************************************/ /* End Of File (foofoo.c) */ /*****************************************************************************/
- コンパイラにより、エラーもしくはワーニングとなるので、最後に改行を必ず入れること。
2.2.11. ヘッダファイルの構成
- 基本は上記の基本構成と同じ。ただし、関数の記述は、禁止する。
- ヘッダファイルを複数箇所でインクルードしてもエラーにならないように、2重読込処置をする。
- 2重読込処理方法
下記の文をヘッダの直後に挿入し、
#ifndef _INCLUDE_COMN_H_ #define _INCLUDE_COMN_H_
下記の文をフッタ部の直前に挿入する。
#endif /* _INCLUDE_COMN_H_ */
「COMN」の部分は、ヘッダファイルのファイル名(.hは除く)を大文字にしたものに置き換える。
2.3. 字下げ(インデント)
インデントは、スペース4文字で行う。スペースとタブの混在は、環境によってずれるので禁止する。
- 制御文の記述では、制御文の各ブロックのネストごとにインデントを行う。
- 関数の呼び出し、制御文の記述で、継続行の持つ場合は、2行目以降にインデントを入れる。
- 変数宣言の際、データ型と変数名の間にインデントを入れる。
2.4. 空白と空行
- 関数内の変数宣言部と手続きの部の間には空行を入れる。
- 関数の手続き部で、ある処理の単位でまとまるように空行を入れる。
- 演算子の前後には空白を入れる。
- セミコロン、カンマの後に文が続く場合は、セミコロン、カンマの直後に空白を入れる。
2.5. コメント
- コメントは、“/*”の後に、“*/”の前に空白を入れ、コメントを囲む。
- “//”で始まる行コメントは極力使用しない。
- コメントは、半角英数字、半角記号および全角日本語とし、半角カナは極力使用しない。
- 「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);
}
- 前処理では、プログラム実行時に必須の処理(ログの開始メッセージ、パラメータの取得、DB接続等)を行う。
- 主処理では、実際の処理を記述して行く。
- 後処理では、プログラム終了時に行う処理(ログの終了メッセージ、DB切断等)を行う。
3. 命名基準
3.1. 変数名
- 一文字の変数名、意味のなさない変数名(aa, a1, a2等)は使用しない。
3.2. 関数名
- 一文字の変数名、意味のなさない変数名(aa, a1, a2等)は使用しない。
3.3. 定義名
- すべて大文字とし、単語間の区切りには、アンダーバー(“_”)を使用する。
4. 文法基準
4.1. 式
4.1.1. 演算子の優先順位
C言語には多くの演算子が存在し、それぞれに明確な優先順位が存在する。しかし、複数の演算子を使用した場合、計算の順序が複雑となる。演算子の優先順位に頼らず、括弧を利用し計算順序がわかりやすくする。
4.1.2. インクリメント、デクリメント
インクリメント(++)演算子、デクリメント(--)演算子は、式の評価前(もしくは後)に加減算を行う。原則、単独で使用し、他の演算子と合わせて使用しない。1つの式で複数の演算子を使用したり、他の演算子と一緒に使用すると、複数の値が変化するので見づらくなる。
4.1.3. 配列
- 配列の添え字にマイナスは使用しない。
- 文字列をセットするchar型配列のサイズで、文字列長が決まる場合は、文字列長+NULL終端分(+1)のサイズ文のみ確保する。また、変数宣言時の要素数の指定は、「文字列長+1」の様に指定する。
- ループなどで配列の要素数を指定する場合は、直値で記述せず、sizeofを使用する。
4.2. 制御文
4.2.1. if文
if文は、2分岐条件文で、式の評価の結果が、真か偽かで処理を分ける制御文である。
- “if”と“(”、 “)”と“{”のそれぞれの間には、半角空白を1文字入れる。
- 始まりのブレス(“{}”)は、if文と同じ行に置き、終わりのブレス(“{}”)は、if文と同じインデント位置にし1行単独で書く。
- 実行する文が1つしかない場合でも、必ずブレス(“{”,“}”)を使用し、ぶら下がり文は禁止する。ただし、“else if”は、例外とする。
- if文の式に、変数の値を変化させる インクリメント、デクリメント および、代入演算子(=,+=等) は使用しない。
- if文の式に、順次演算子(“,”)、条件演算子(“? :”) は使用しない。
- if文の式に、関数の記述は、戻り値を比較する場合を除いて禁止する。
4.2.2. switch文
switch文は、多分岐選択条件文で、式の評価し一致する定数式のcaseキーワードに制御を移す制御文である。
- “switch”と“(”、“)”と“{”のそれぞれの間には、半角空白を1文字入れる。
- “case”、定数式、“:” および “default”、“:”のそれぞれの間にも、半角空白を1文字入れる。
- 始まりのブレス(“{}”)は、switch文と同じ行に置き、終わりのブレス(“{}”)は、switch文と同じインデント位置にし1行単独で書く。
- case、defaultキーワードは、インデントを1つ下げ、それぞれの文は、更にインデントを1つ下げる。
- 1つのcaseキーワードには、1つの定数式しか記述できない。従って、複数の定数式で同一の処理を行う場合は、caseキーワードの行を並べて記述する。
- C言語のswitch文は、実行すべき文の選択ではなく、制御を移すべき場所の選択である。よって、breakを記述しないと、後続の文も実行されてしまう。そのため、2つ目以降のcaseおよびdefaultキーワードの前には、break文を入れる。意図的に後続の文も実行させるためにbreak文を記述しない場合は、その旨をコメントとして記述する。
- switch文の式に、変数の値を変化させる インクリメント、デクリメント および、代入演算子(=,+=等) は使用しない。
- switch文の式に、順次演算子(“,”)、条件演算子(“? :”) は使用しない。
4.2.3. while文
while文は、一定条件下での繰り返しを行う、繰り返し文である。
- “while”と“(”、“)”と“{”のそれぞれの間には、半角空白を1文字入れる。
- 始まりのブレス(“{}”)は、while文と同じ行に置き、終わりのブレス(“{}”)は、while文と同じインデント位置にし1行単独で書く。
- 実行する文が1つしかない場合でも、必ずブレス(“{”,“}”)を使用し、ぶら下がり文は禁止する。
- while文の式に、変数の値を変化させる インクリメント、デクリメント および、代入演算子(=,+=等) は、原則使用しない。
- while文の式に、順次演算子(“,”)、条件演算子(“? :”) は使用しない。
- while文の式に、関数の記述は、戻り値を比較する場合を除いて禁止する。
4.2.4. do-while文
while文と同様の繰り返し文である。ただ、while文と違い、先に文を実行しその後に式の評価が行われる。
do-while文は、使用しない。
4.2.5. for文
for文は規定の回数の繰り返しを行う、繰り返し文である。
- “for”、“(”、初期設定式、“;”、実行判定式、“;”、再設定式、“)”、“{” のそれぞれの間には、半角空白を1文字入れる。
- 始まりのブレス(“{}”)は、for文と同じ行に置き、終わりのブレス(“{}”)は、for文と同じインデント位置にし1行単独で書く。
- 実行する文が1つしかない場合でも、必ずブレス(“{”,“}”)を使用し、ぶら下がり文は禁止する。
- 初期設定式には、繰り返しの回数を制御するループ制御変数の初期化のみを行う。
- 実行判定式には、ループ制御変数の繰り返しの条件式のみを行う。
- 再設定式には、ループ制御変数の加減算のみを行う。
- for文の各式は、省略しない。省略する場合は、その旨をコメントとして残す。
- for文の各式に、順次演算子(“,”)、条件演算子(“? :”) は使用しない。
- for文の各式に、関数の記述は、使用しない。
4.2.6. break文とcontinue文
break文は、最も内側のswitch, while, do-while, for文を終了し、その制御を抜ける。continue文は、最も内側のwhile, do-while, for文の残りを実行せず、次の繰り返しを実行する。
- 繰り返し文からある条件下で抜ける場合は、switch文を使用せず、if文を使用する。switch文のブロック内にbreak文を記述しても、switch文を終了するだけで、ループを抜け出せないので注意が必要である。
4.2.7. return文
return文は、関数の実行を終了し、呼び出した関数に制御を移す文である。
- 同一関数内で複数のreturn文の記述は禁止とし、関数の最後に記述する。
- void型関数の場合、“return;”と記述する。
- void型関数以外の場合は、“return(式);”と記述する。式は、関数の型に合ったリテラル値 もしくは、変数にする。
- return文の中での演算は原則禁止とする。
4.2.8. goto文とラベル
ラベル及びgoto文の使用は原則禁止とする。
5. Pro*C
5.1. 全般
- ソース内に記述するSQL文はすべて大文字で記述する。
- 項目名、別名等に、予約語、小文字、全角文字を使用する場合は、ダブルクォーテーションで囲む。
- SQL文が短く1行で書く場合は、「EXEC SQL 〜SQL文〜;」と記述する。
- 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. ホスト変数宣言
- ホスト変数は、すべてDECLARE SECTION内で宣言する。
- ホスト変数には、変数名のプレフィックスとして“H_”をつける。
- DBの項目と対になるホスト変数名は、項目名をそのまま使用する。
- ホスト変数のデータ型は、原則以下に従う。文字列のサイズは、必要分のみとする。
- インジケータ変数の変数名は、対になるホスト変数と同名とし、プレフィックスは、“H_”代わりに“I_”を付ける。
- 構造体を使用する場合には、メンバー名にはプレフィックスの“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文を指定し、アクションを決める方法があります。
- WHENEVER文は使用せず、SQLCODEの値でエラー処理を行う。
5.4. プリコンパイラオプション
ProCのオプションにはいくつがあります。以下は、指定する。但し、デフォルトで有効な場合は特に指定しなくてよい。
- 「LINE=YES」を指定し、Cソース内に「#line」を挿入させる。Cのコンパイルエラー時にProCのソースコードの行数で表示されるようになるため、修正しやすくなる。
- 「PARSE=NONE」を指定し、EXEC SQL以外の部分の構文解析をしないようにする。他の指定では、Cソースすべてが解析しようとする。そのため、行コメントが使えない。インクルードディレクトリをすべて指定する必要がある。などの制限が多くなる。
- 「MODE=ORACLE」を指定し、Oracleモードで動作するようにする。ANSIモードでは、カーソルオープンをしたまま、コミットが出来ない等制限が多い。
- 「SQLCHECK=SEMANTICS USERID=user/pass@tsn」を指定し、プリコンパイル時に項目名等のチェックも行うようにする。但し、接続するDBがない場合やテーブルがない場合、項目名にCASEが存在する等でSQL文があっているのにエラーになる場合は、「SQLCHECK=SYNTAX」を指定する。
- 「CHAR_MAP=CHARZ」を指定し、DBの値をchar型のホスト変数へセット方法を指定する。
最終更新時間:2008年11月14日 00時35分00秒 指摘や意見などあればSandBoxのBBSへ。