API03-C. 関連する関数にはインタフェースと機能に一貫性を持たせる
単一ライブラリを構成する関数群など関連性のある関数は、インタフェースを、一貫性があって使いやすくすべきである。ラルフ・ウォルド・エマーソンは「愚かな一貫性は小人物に憑いたおばけである」という言葉を残したが、関数のインタフェースや動作に一貫性がないと誤用しかねないため、これは「賢明な一貫性」であるといえる。関数のインタフェースに一貫性を持たせる方法の一つは、一貫性があり使いやすいエラー検査方法を提供することである。詳細については「API04-C. 一貫性があり使いやすいエラー検査方法を提供する」を参照。
違反コード (インタフェース)
一貫性のないインタフェースの実例を見つけたければ標準 C ライブラリを探せばよい。標準 C ライブラリは、複数のライブラリを統合したものであり、元になったライブラリのスタイルや厳格性の程度は異なる。たとえば、fputs()
(C 言語標準、セクション 7.21.7.4 [ISO/IEC 9899:2011] で規定)は fprintf()
(セクション 7.21.6.1 で規定)との関連性が強いが、関数宣言を見ると明らかなように、fputs()
は最後の引数としてファイルハンドルを渡すが、fprintf()
は最初の引数としてファイルハンドルを渡す。
int fputs(const char * restrict s, FILE * restrict stream); int fprintf(FILE * restrict stream, const char * restrict format, ...);
引数の順序は、たとえば次のようなマクロで簡単に変更できる。
#include <stdio.h> #define fputs(X,Y) fputs(Y,X)
ただし、C 言語規格のセクション 7.1.3 によると、標準ライブラリ関数、型、マクロなどの予約済みの識別子と同じ名前のシンボル(マクロを含む)を定義するプログラムの動作は、未定義である。
一貫性のないインタフェースを使用しているとコードが読みにくくなり、たとえば、ある規則に従うコードとそうでないコードを読む際に混乱が生じる。
適合コード (インタフェース)
POSIX スレッドライブラリ [Butenhof 1997] が定義するインタフェースは、その他のPOSIX ライブラリが採用する既存のコーディングスタイルと一貫性がある。たとえば、すべての初期化関数は一貫したパターンに従っており、第1引数は初期化するオブジェクトへのポインタとし、続いて引数が存在する場合、それを属性として初期化に使用する。
/* Pthread 属性オブジェクトの初期化 */ int pthread_condattr_init(pthread_condattr_t *); int pthread_mutexattr_init(pthread_mutexattr_t *); int pthread_rwlockattr_init(pthread_rwlockattr_t *); ... /* 属性を使用した Pthread オブジェクトの初期化 */ int pthread_cond_init(pthread_cond_t * restrict, const pthread_condattr_t * restrict); int pthread_mutex_init(pthread_mutex_t * restrict, const pthread_mutexattr_t * restrict); int pthread_rwlock_init(pthread_rwlock_t * restrict, const pthread_rwlockattr_t * restrict); ...
関数の引数のうち、変更されないオブジェクトを参照する引数は、const
宣言される。第1引数で参照されるオブジェクトは関数で変更されるため、const
ではない。データの抽象化を行う関数では、抽象データ型に対するハンドルを第1引数として定義するのが理にかなっている(「DCL12-C. 抽象データ型は opaque な型を使って実装する」を参照)。属性オブジェクトへのポインタを引数に取る初期化関数は、ポインタが NULL
である場合にデフォルト値を属性として使用する。
違反コード (動作)
VMware 仮想化インフラストラクチャ(VIX)API の共有フォルダ関数とファイルコピー関数は、フォルダ名として使用可能な文字集合に一貫性がない。そのため、VixVM_CopyFileFromHostToGuest()
などのファイルコピー関数で使用できない共有フォルダを作成できてしまう。
適合コード (動作)
共通のオブジェクトに対する処理を行う関数の動作には一貫性を持たせ、ある関数によって作成もしくは変更されたオブジェクトが、関連する別の関数によって正常に処理されるようにすべきである。
リスク評価
複数の関数間でインタフェースと機能の一貫性を維持しないと、型に関するエラーが発生する可能性がある。
ルール |
深刻度 |
可能性 |
修正コスト |
優先度 |
レベル |
---|---|---|---|---|---|
API03-C |
中 |
低 |
中 |
P4 |
L3 |
関連するガイドライン
ISO/IEC 9945:2003 | |
ISO/IEC 23360-1:2006 | |
ISO/IEC TR 24731-1 | |
ISO/IEC TR 24731-2 | |
MISRA C:2012 | Rule 21.3 (required) Directive 4.12 (required) |
参考資料
[Burch 2006] | |
[CERT 2006c] | |
[Miller 1999] | |
[Seacord 2013] | Chapter 2, "Strings" |
[VMware 2007] | VIX API Version 1.1.1 (for Workstation 6.0.1) Release Notes, August 16, 2007 |
翻訳元
これは以下のページを翻訳したものです。
API03-C. Create consistent interfaces and capabilities across related functions (revision 27)