9

私はC(共有)ライブラリを書いています。staticそれは、外部モジュールから隠すために、いくつかのグローバル変数を定義できる単一の変換ユニットとして始まりました。

ライブラリが大きくなったので、モジュールをいくつかの小さなソースファイルに分割したいと思います。問題は、前述のグローバルに対して2つのオプションがあることです。

  1. 各ソースファイルにプライベートコピーを作成し、関数呼び出しを介してそれらの値を同期します。これは非常に醜くなります。

  2. 定義を削除してstatic、変数が-を使用してすべての変換ユニット間で共有されるようにします。externただし、必要な宣言が行われている場合、ライブラリに対してリンクされているアプリケーションコードがこれらのグローバルにアクセスできるようになります。

それで、プライベートグローバル変数を複数の特定の変換ユニット間で共有するためのきちんとした方法はありますか?

4

4 に答える 4

10

GCCの可視性属性拡張が必要です。

実際には、次のようなものです。

 #define MODULE_VISIBILITY  __attribute__ ((visibility ("hidden")))
 #define PUBLIC_VISIBILITY  __attribute__ ((visibility ("default")))

(おそらく#ifdef、いくつかの構成トリックautoconfや他のautotoolsを使用して、上記のマクロが必要です。他のシステムでは、などのような空の定義があります#define PUBLIC_VISIBILITY /*empty*/...)

次に、変数を宣言します。

int module_var  MODULE_VISIBILITY;

または関数

void module_function (int) MODULE_VISIBILITY;

その後、共有ライブラリの内部で使用module_varまたは呼び出すことができますが、外部では使用できません。module_function

GCCの-fvisibilityコード生成オプションも参照してください。

ところで、ライブラリ全体をコンパイルして通常どおり-Dsomeglobal=alongname3419a6に使用することもできます。someglobal実際にそれを見つけるには、ユーザーが同じプリプロセッサ定義をコンパイラに渡す必要があります。名前をalongname3419a6ランダムでありそうにないものにして、衝突を起こりにくくすることができます。


PS。この可視性は、GCC(およびおそらくLinux上のELF共有ライブラリ)に固有です。GCCなしでは、または共有ライブラリの外部では機能しません。Linux固有です(GCCを備えたSolarisなど、他のいくつかのシステムに搭載されている場合でも)。おそらく、他のいくつかのコンパイラ(LLVMclangから)は、共有ライブラリ(静的ライブラリではない)のLinuxでもサポートしている可能性があります。実際、(単一の共有ライブラリの複数のコンパイルユニットに対する)実際の非表示は、ほとんどがリンカーによって実行されます(ELF共有ライブラリで許可されているため)。

于 2013-03-15T14:42:22.137 に答える
5

最も簡単な(「昔ながらの」)解決策は、目的のパブリックヘッダーで変数を宣言しないことです。

ライブラリヘッダーを「header.h」と「header-internal.h」に分割し、後者で内部のものを宣言します。

もちろん、ライブラリグローバル変数の名前を保護して、ユーザーコードと衝突しないように注意する必要があります。おそらく、この目的の関数に使用するプレフィックスがすでにあるはずです。

変数をでラップして、structよりクリーンにすることもできます。これにより、実際のシンボルが1つだけグローバルに表示されます。

于 2013-03-15T14:51:45.177 に答える
2

情報を可能な限り隠したい場合は、偽装された構造体で物事を難読化することができます。例:ヘッダーファイル、

struct data_s {
   void *v;
};

そしてあなたの情報源のどこか:

struct data_s data;
struct gbs {
   // declare all your globals here
} gbss;

その後:

data.v = &gbss;

その後、次の方法ですべてのグローバルにアクセスできます。((struct gbs *)data.v)->

于 2013-03-15T15:08:25.180 に答える
0

これは文字通り意図したものではないことはわかっていますが、グローバル変数を静的のままにして、複数のソースファイルに分割することができます。

静的と宣言された同じソースファイル内の対応する静的変数に書き込む関数をコピーします。

同じモジュールの外部ソースファイルがその値を読み取れるように、静的変数を読み取る関数を宣言します。

ある意味でグローバル性を低下させます。可能であれば、大きなファイルを小さなファイルに分割するための最良のロジックは、データに基づいてその決定を行うことです。

この方法でそれを行うことができない場合は、すべてのグローバル変数を静的として1つのソースファイルにバンプし、関数によってモジュールの他のソースファイルからそれらにアクセスして、誰かがグローバル変数を操作している場合に公式にします。少なくともあなたはその方法を知っています。ただし、@unwindのメソッドを使用する方がおそらく良いでしょう。

于 2017-08-15T12:25:31.397 に答える