[ << ] [ >> ]           [Top] [Contents] [Index] [ ? ]

7. インターフェース設計に対する助言

良いライブラリインターフェースと書くことは,多くの経験とライブラリが解 決する問題への完全な理解が必要です.

良いインターフェースを設計した場合,頻繁に変更する必要がなく,ドキュメ ントを更新し続ける必要がなく,ユーザはライブラリの使用方法を何度も学習 する必要がありません.

ここにライブラリインターフェースの設計に関するヒントの短いリストがあり, それは仕事上で役立つでしょう.

計画前

エントリポイントを頻繁に削除する必要がないように,すべてのインターフェー スを本当に最小限にするように試みてください.

インターフェースの変更を避ける

エントリポイントの再設計と変更を地獄のように繰り返すのが好きな人もいま す(注意:関数の名前変更はエントリポイントの変更と考えられます). インターフェースを再設計する必要がある場合,ユーザが既存のコードを書き 換える必要がないように,互換機能を残すことを試みてください.

不透明なデータ型の使用

ライブラリユーザがアクセスするデータ型の定義は,少ないければ少ないほど 良いでしょう.可能な場合,一般的な(内部データにキャスト可能な)ポインタ を受け入れる関数を設計し,ライブラリユーザが直接データを操作するのを許 可するのではなく,アクセスする関数を提供してください.そうすることで, インターフェースを変更せずに,データ構造を変更することが自由になります.

これは,本質的にオブジェクト指向のシステムで抽象的なデータ型と継承を使 用するのと同じです.

ヘッダファイルの使用

ライブラリのグローバル関数と変数のそれぞれのドキュメントをヘッダファイ ルに注意して書いていて,ライブラリソースファイルに含めている場合,コン パイラは偶然にインターフェースの変更の有無を知らせるでしょう(see section Cヘッダファイルを書く).

可能な場所でのstaticキーワード(またはその等価物)の使用

ライブラリが持つグローバル関数は,減らせば減らすほど,より柔軟に変更で きます.スタティック関数と変数は,形式を変更したいとき変更できます …ユーザはそれらにアクセスできず,そのためインターフェースは変更 されません.

配列の次元に対する注意

大域的な配列の要素数は,たとえヘッダでextern int foo[];と宣言し ていたとしても,それはインターフェースの一部です.これはi386とその他の SVR4/ELFシステムでは,アプリケーションが共有ライブラリのデータを参照す る時,データのサイズ(と型)はアプリケーションの実行形式に含められます. 配列や文字列の大きさを変更したくなければ,配列ではなくポインタとして提 供してください.


7.1 Cヘッダファイルを書く

移植性の高いCヘッダファイルを書くことは難しく,それは異なる形式のコン パイラで読まれる可能性があるためです.

C++コンパイラ

C++コンパイラは,Cより強固に形式化されているため,完全なプロトタイプで 宣言された関数を要求します.C関数と変数は,名前がおかしくならないよう に,extern "C"ディレクティブで宣言する必要があります.libtool でC++の使用に関連したその他の問題は,See section C++に対するライブラリを書く.

ANSI Cコンパイラ

ANSI Cコンパイラは,C++コンパイラほど厳密ではありませんが,関数のプロ トタイプは,ヘッダファイルを#includeしたときの不必要な警告を避 けるため,行う方が良いでしょう.

非ANSI Cコンパイラ

Non-ANSIコンパイラは,関数がプロトタイプされている場合,エラーを報告し ます.

これらの複雑さは,上記それぞれのコンパイラを利用可能にするため,ライブ ラリインファーフェースヘッダで,いくつかのCプリプロセッサの魔法を使用 する必要があることを意味します.

libtool配布物の`demo'サブディレクトリの`foo.h'は,安全にシス テムディレクトリにインストール可能な,ヘッダファイルの書き方の例を提供 します.

そのファイルの関連する部分は,以下のようになっています.

 
/* BEGIN_C_DECLS should be used at the beginning of your declarations,
   so that C++ compilers don't mangle their names.  Use END_C_DECLS at
   the end of C declarations. */
#undef BEGIN_C_DECLS
#undef END_C_DECLS
#ifdef __cplusplus
# define BEGIN_C_DECLS extern "C" {
# define END_C_DECLS }
#else
# define BEGIN_C_DECLS /* empty */
# define END_C_DECLS /* empty */
#endif

/* PARAMS is a macro used to wrap function prototypes, so that
   compilers that don't understand ANSI C prototypes still work,
   and ANSI C compilers can issue warnings about type mismatches. */
#undef PARAMS
#if defined (__STDC__) || defined (_AIX) \
        || (defined (__mips) && defined (_SYSTYPE_SVR4)) \
        || defined(WIN32) || defined(__cplusplus)
# define PARAMS(protos) protos
#else
# define PARAMS(protos) ()
#endif

これらのマクロは,以下のように`foo.h'で使用されます.

 
#ifndef FOO_H
#define FOO_H 1

/* The above macro definitions. */
#include "…"

BEGIN_C_DECLS

int foo PARAMS((void));
int hello PARAMS((void));

END_C_DECLS

#endif /* !FOO_H */

`#ifndef FOO_H'が,`foo.h'の本体を,与えられたコンパイルで一 回以上読み込むことを避けることに注意してください.

また,BEGIN_C_DECLS/END_C_DECLSの組の外側あるものだけが, #include行にあります.厳密にいうと,それは,保護が必要なCのシン ボル名ですが,ヘッダの内容の中心周辺にこれらのマクロの単一の組がある場 合,ヘッダファイルはより管理しやすくなります.

PARAMSBEGIN_C_DECLS,そしてEND_C_DECLSのこれら の定義を独自のヘッダで使用すべきです.そして,C++,ANSI,そして非ANSI のコンパイラ(7)で有効なヘッダファイルを作成するために,そ れらを使用することが可能となります.

移植可能なコードをネイティブに書かないでください,上記のヒントに続ける ことで,最も明白な問題を無くすことに役立ちますが,明らかに別の微妙な問 題があります.以下の問題に対処する必要があるかもしれません.


[ << ] [ >> ]           [Top] [Contents] [Index] [ ? ]

This document was generated by Akihiro Sagawa on June, 15 2005 using texi2html 1.70.