2016-07-13 13 views
-1

私の理解では、ELFオブジェクトファイルのシンボルはメモリアドレスの名前に過ぎません。言い換えれば、シンボル名を指定すると、リンカはC言語で宣言されている型にかかわらず、常に同じアドレスを参照する必要があります。externポインタで外部関数を宣言するエラー

私はそうではないと考えました。以下の例を参照:

/* a.c */ 
extern void *foo; 
extern void *bar; 
void main() { 
    printf("foo: %p, bar: %p\n", foo, bar) 
} 

/* b.c */ 
void foo(void) { 
} 
void bar(void) { 
} 

上記プログラムの出力は言うfooと同じ場所にbar点(1)。また、この場所はfooまたはbarのアドレスとは異なるものです。注(1)そうでない変換ミス

Iは、関数ポインタ(例えばextern void (*foo)(void))にfoobarの種類を変更しようとしたならないことを示し、出力は同じです。

もちろん、正しい宣言extern void foo(void)で動作します。

私の理解に間違いがありますか?ありがとう。あなたはシンボルfoobarが参照アドレスを印刷していない

+1

「この場所は、fooまたはbarの住所が「何にすべきか」とはまったく異なります。 –

+0

@DanFego:-ffree-standingオプションでコンパイルするときにこの問題が発生したので、関数の正確な位置を知ることができました。 –

+1

「extern void foo(void);」や「extern void bar(void)」のようなことをやっていないのはなぜですか? –

答えて

2

(私は物事を動作させるためにだけではなく、私の理解を修正しようとしている)が、foobarのアドレスの値。

extern void *foo; 
extern void *bar; 

void main() { 
    printf("foo: %p, bar: %p\n", &foo, &bar); 
} 
0

まず最初に:

あなたはこのような何かをする必要があり bar fooのアドレスを印刷し、するには宣言は

void foo(void); 
void bar(void); 

機能がデフォルトですでにexternにしているになるはず。別のファイルで宣言している間にexternを追加する必要はありません。 extern void *fooは、他のファイルにポインタfooを宣言し、このファイルで使用していることを意味します。他のファイルのポインタはvoid *fooと宣言していません。

と同じアドレスを得ることについて

:2関数や変数か何かで同じ仮想アドレスを持つことができますが、彼らはメモリの異なる領域(異なる物理アドレス)にマッピングされます。 %pから印刷すると、物理アドレスではなく仮想アドレスが取得されます。あなたが別の翻訳単位内の異なるタイプの識別子として foobarを宣言するため

2

あなたのコードは未定義の動作が含まれています。これは、ISO 9899:2011§6.2.7¶2の違反です。

同じオブジェクトまたは関数を参照するすべての宣言は、互換性のある型を持ちます。 この動作は未定義です。

静的記憶域の変数にアクセスすると、シンボルに格納されている値(グローバル変数の内容)を取得するために逆参照されます。シンボル自体は、静的変数のアドレスだけです。シンボルの値を取得するには、シンボルの値であり、変数のアドレスを取るために&演算子を使用する必要があります。

あなたの混乱の原因になっているかもしれませんが、これは機能のためには必要ありません。&は必要に応じて自動的に散在します。 ISO 9899:2011§6.3.2.1¶4:

機能指名は、関数型を持つ式です。それはsizeofオペレータの オペランドである場合を除いて、_Alignofオペレータ、65)または単項&オペレータ、型の関数指定子は、「タイプを返す関数は、」機能への」ポインタを入力した式に変換され戻り値の型。

65)  この変換が発生しないので、sizeof又は_Alignof演算子のオペランドは機能指示のままであり、6.5.3.4での制約に違反。

これはあなたの質問をクリアすることを願っています。

関連する問題