これはC固有の質問です。 .h
ファイルを介していくつかの関数のみを公開し、翻訳ユニットの境界内で可能な限りすべてを維持しようとしています。つまり、ファイルレベルのオブジェクトにstatic
リンケージを与えています。
ここで、いくつかの関数を他のモジュールから呼び出す必要がありますが、直接呼び出す必要はありません。私のモジュール/ファイル/翻訳ユニットは他のモジュールをサブスクライブし、関数へのポインターを渡します。次に、特定のイベントで、いくつかの引数を使用してポインターが呼び出されます。
したがって、これらの関数があいまいな場所から呼び出されていることを非常に明確にする方法を考えています。
static
またはextern
である必要がありますか(そしてそれらを.h
で公開します)?コンパイル単位(ファイル)の観点から、あなたが気にかけるべき唯一のことは、関数が外部で利用可能であるかどうかです。それを使用可能にすることは、それが呼び出されることを意図していたことを意味し、それらの呼び出しが発生することを想定して操作する必要があります。関数自体に関する懸念は、そのエントリポイントから始まります。そもそも制御がどのようにそこに到達するかは、それを実現するコードにのみ重要です。
私が知っているCのすべての実装におけるリンケージはシンボリックであるため、関数を呼び出すものはすべてそのシンボルを参照する必要があります。
_foo(); /* Direct */
some_function_pointer_t funcs[] = { &foo, &bar, &baz }; /* Indirect */
_
foo()
を誤ってstatic
と宣言した場合、プログラムはリンクされません。 static
以外と宣言すると、呼び出されない公開された関数があります。関数が使用されているかどうかに関する質問は、オブジェクトファイルのシンボルテーブルをダンプするか、ソース内で検索することで解決できます。
そのため、これらの関数が不明瞭な場所から呼び出されていることを非常に明確にする方法を探しています。
「あいまい」を定義します。
メソッドは明確に定義された「インターフェース」を通じて公開する必要があり、Shivan Dragonがすでに示唆しているように、それらの「インターフェース」are .hファイル。別のプログラムに「正しい」ヘッダーファイルを指定しないと、メソッドを呼び出すことができません。
それらは静的であるか外部である必要がありますか(そしてそれらを.hで公開する必要があります)?
static
mightインスタンスデータを含むクラス[のような構成]がない限り、問題ありません。extern
はyo実際にはまったく実装しないことを意味します。リンクプロセス中に、他の場所から実装が「取得」されます。
関数の名前にいくつかのヒントを含める必要がありますか?
それとも、「Xによって呼び出された」というコメントを入れるだけで十分ですか?
絶対違う。
このようなコメントは、どんなに意味のあるものであっても、書き終えた瞬間に時代遅れになります。
私はまだそれらをstatic
にし(それらは誰にでもリンクされて呼び出されることを意図していません)、それらの目的をそれらの名前で外部関数に提供されるコールバックとしてマークします。
static
隠すことができるものを、隠すことができる限り隠そうとしているからです。
A)、コメントが古くなっている、およびb)コールバックが提供された場所で、この関数がそのように使用されることが意図されていることが明らかになったため、名前にそれらをマークします。命名規則に従わない関数のアドレスを取得している。
スコープ修飾子は、「十分に近い」ドキュメントの形式としてではなく、主にコンパイラの情報として使用する必要があります。特にstatic
を使用すると、Cコンパイラは、現在のコンパイラで動作する場合でも、コールバックとしても含めて、モジュールの外部から関数を使用できなくすることができます。
もちろん、コードにコメントを追加する必要があります。これは、混乱を招く可能性がある状況であることがわかるためです。異常または予期しないものには、適切なコメントが必要です。しかし、他の回答で述べられているように、コメントは未読になったり、古くなったりする可能性があります。
したがって、残っている唯一のオプションは、関数に名前を付けて、それがコールバックであることを示すことです。私が見たほとんどの例は_callback
または_cb
接尾辞、またはcb_
を接頭辞として。コードでコールバックが異常な場合は長い形式を使用し、一般的な場合は短い形式を使用します。
モジュール内でコールバック関数が定義されていて、ユーザーが自分のものを提供しない場合は、初期化フェーズでプレースホルダーを使用できると思います。プレースホルダーは通常、enum
であり、内部で適切なstatic
関数に変換されます。