3

構造体を使用する .c ファイルでのみ表示される構造体型を宣言することは可能ですか? 外部データ オブジェクトの前にstaticを配置することで、変数のリンケージが内部に変更されることを私は知っています。しかし、次のように、新しい構造体型の宣言の前にstaticを置くことは可能ですか?

static struct log{
            ...;
            ...;
};
typedef struct log log;

上記のようにログなどの構造タイプを「プライベート」にすることができない場合、他のソースファイルが構造の名前 (私の例ではログ) の存在を認識していなくても、ということですか? 、いくつかの変数ログに名前を付けると、偶発的な名前の衝突が依然として発生する可能性があります(すべてのオブジェクトファイルをリンクすると仮定します)?

編集:コンパイラ/リンカーの仕組みに慣れていません。グローバル変数名logがあり、グローバル変数を含むファイルが、構造logが定義されている唯一のソース ファイルにリンクされている場合、リンク時に混乱が生じることはありません。1 つのログは変数名であり、別のログは別のログです。型名ですか?

4

4 に答える 4

9

いいえ。structプライベートにする唯一の方法は、それを使用するファイルでのみその定義を利用できるようにすることです。共通のヘッダー ファイルには入れないでください。1 つのソース ファイルでのみ使用されている場合は、そのソース ファイルで定義するだけですが、複数のソース ファイルで使用されている場合は、難しい問題があります。各ソース ファイルで定義することはできますが、変更を加えるときは、その各インスタンスを変更することを忘れないでください。または、プライベート ヘッダー ファイルで定義して、それらのソース ファイルのみにプライベート ヘッダーが含まれるようにすることもできます。

異なるソース ファイルでの名前の衝突は、それらが相互に干渉しようとしない限り問題ありません。あるファイルにがstruct log定義されていて、別のファイルに の異なる定義があるstruct log場合は、一方を他方に渡さないでくださいlog。C では、構造体名はオブジェクト ファイル内のシンボル名の一部にはなりません。特に、C では関数のオーバーロードが違法であるため、(C++ のように) パラメーターの型を含めるための関数名の名前マングリングはありません。

于 2012-10-31T20:20:27.127 に答える
3

No.staticは収納タイプです。変数宣言の外側の型に適用しても意味がありません。

struct logヘッダー ファイルで定義したくない場合は、その必要はありません。typedef を次のように書くだけです。

typedef struct log log;

log *ポインターのみを扱う限り、これで十分です。ただし、構造体のサイズは含まれるものに依存するため、 a log(または take )を宣言するには、構造体の完全な定義が必要です。sizeof(log)

名前の競合に関しては、構造体と型はリンカーによって管理されないことに注意してください。リンカーは、関数や変数など、グローバルに表示されるシンボルのみを考慮します。そうは言っても、特には標準ライブラリの数学関数であるmylib_log_tため、混乱を避けるために、おそらく型名に接頭辞 ( など) を適用する必要があります。log

于 2012-10-31T20:22:53.087 に答える
0

これを書く理由があります:

static int a;

リンカーaがそれを他の場所で定義されたものと組み合わせるのを防ぐためです。リンカー
はsとは関係がないため、別の c ファイルを入れる心配はありません。 異なる c ファイルにある限り、名前の混乱はありません。struct

于 2012-10-31T20:28:41.203 に答える
0

これは一般的にはありえません。しかし、一部のコンパイラで機能する可能性のあるハックを思いつくことができます。

これが難しい理由は、構造体のインスタンスを引数として関数呼び出しを生成するために、C コンパイラが構造体がどのように見えるかを知る必要があるためです。

したがって、次のヘッダーを使用してライブラリを定義するとします。

struct foo {
    int32_t a, b;
};

foo make_foo(int arg);

foo do_something(foo p1, foo p2);

次に、 を呼び出すプログラムをコンパイルするにはdo_something、コンパイラは通常、構造体 foo がどのようなものかを知る必要があります。これにより、引数として渡すことができます。コンパイラーは、構造体の一部をレジスター経由で渡し、一部をスタック経由で渡すなど、あらゆる種類の奇妙なことをここで行うことができるため、構造体がどのように見えるかを実際に知る必要があります。

ただし、一部のコンパイラでは、スタックを介して構造体を完全に渡す必要があることを示すことができると思います。たとえば、 i386 をターゲット アーキテクチャ ( docsregparm(0) )として使用している場合、 function 属性は GCC で機能するはずです。

そのような状況では、次のようなことができるはずです: ヘッダー ファイルの「パブリック バージョン」を作成し、そのファイルで、完全な構造体をレイアウトする代わりに、それの未分化バージョンを作成します。

struct foo {
    uint8_t contents[SIZE_OF_STRUCT_FOO];
}

whereSIZE_OF_STRUCT_FOOsizeof(struct foo)、通常の方法で構造体を定義したときに返されるものです。基本的に、「foo」はSIZE_OF_STRUCT_FOOバイトを含む構造体であると言っています。次に、呼び出し規約がこれら 2 つの構造体を同じように扱う限り、機能するはずです。

于 2014-10-27T18:08:26.050 に答える