この記事について
C/C++言語において、品質を向上するためのコツについて記載します。本記事では品質向上を考慮した関数定義の方法について記載します。
関数定義のコツ
関数を定義する場合、通常は引数は関数の入力、関数の戻り値に出力を定義するようになっていますが、品質を考えた場合に、関数の機能に関わらず、呼び出し元に関数でエラーが発生したかどうかの情報も取得できるようにする必要があります。
この時、各関数でエラー情報の出力方法が異なっていると、呼び出し元でのエラー処理漏れなどにつながり品質を低下させる恐れがあります。
これを防ぐために、関数の戻り値はエラーを表すように統一すると、エラー処理忘れなどを防ぐことができ品質向上に貢献できます。この場合、関数から戻り値を得たい場合は、呼び出し元より関数の引数で与えた領域に返してもらうようにすることで達成します。
C言語の場合、以下のようなパターンで関数を定義します。
関数定義のパターン
//--------------------------------------
// 入力なしの関数の定義
//--------------------------------------
// 規定パラメータの設定処理など、必ず成功する関数の場合のみ採用します
void function(void);
void function(Type* p_output);
//--------------------------------------
// 入力ありの関数定義
//--------------------------------------
// 入力がある場合、関数作成者ではコントロールできないエラーが
// 発生する可能性があるため、エラー情報は必ず返すようにします
Error function(const Type* p_input);
Error function(const Type* p_input, Type* p_output);
エラー型(Error)の定義は例えば、以下のようにdefineすることで定義できます。
# ifndef Error
# define Error uint32_t
# else
/* すでにdefineされていた場合のエラー処理 */
# endif
具体的なエラーは以下のように定義することができます。
エラー種別の定義例
// 成功は0で定義します
# define E_SUCCESS (0x0000)
// 各種エラーの種別を定義します
// 先頭バイトで種類分けするとエラー種別の追加などで拡張する際に整理しやすくなります
# define E_SYSTEM_ERROR (0x1000)
# define E_IO_ERROR (0x2000)
# define E_IO_ERROR_NEW_FILE (0x2001)
# define E_IO_ERROR_OPEN_FILE (0x2002)
// エラー判定用のマクロは以下のように定義できます
# define E_IS_SUCCESS(err) ((err) == E_SUCCESS)
# define E_HAS_ERROR(err) ((err) != E_SUCCESS)
この定義を使ったファイルを作成するプログラムの例を示します。
記載が多少冗長にはなりますが、書き方が統一されることでレビューなどで
エラー処理漏れが検出しやすくなり、品質向上に貢献できるようになります。
関数定義の適用例
# include <error_type.h>
Error create_file( const char* filename, FILE** pp_fp){
FILE* p_tmp;
p_tmp = fopen(filename, "w");
if( NULL == p_tmp ){
// fopen()がNULLを返却したということに対して
// エラー番号を返すことで意味を付加して呼び出し元に通知できます
return E_IO_ERROR_NEW_FILE;
}
else{
}
// 成功した場合のみ、戻り値の領域を変更します
*pp_fp = p_tmp;
return E_SUCCESS;
}
int main(void){
Error err;
FILE* p_file = NULL;
const char* filename = "sample.txt";
// 入力(引数)がある関数は必ずエラーを返すルールにより
// エラー処理漏れがわかりやすくなります
err = create_file( filename, &p_file );
if( E_HAS_ERROR(err) ){
printf("Open Error!")
}
else{
// ファイルオープン成功
}
return 0;
}