3

純粋な C、RHEL 5.5 x64、gcc バージョン 4.1.2 20080704 (Red Hat 4.1.2-48) でいくつかのコードを書いています。

2 つの静的ライブラリを使用してコンパイルされた実行可能ファイルがあります。それらのそれぞれは、いくつかのグローバルな(特定のライブラリの)配列変数を使用します(つまり、ある.cファイルで char var1[VAR_SIZE1];.cファイルを使用し、次に使用するライブラリの他の.cファイルでextern char var1[VAR_SIZE1];、2番目のライブラリと同じ状況です)。各ライブラリは、実行可能なソース ディレクトリの独自のサブディレクトリに配置されます。あるライブラリがそのデータを別のライブラリのメモリに配置できることに気付き始めました。何が起こっているのかを知るために、3 番目の lib の変数の 1 つに void ポインターを定義し (lib 3 は問題の両方の lib で使用されます)、このポインターに lib1 のアドレスを割り当て、lib2 のアドレスを調べました。私が今見ているのは:

char var1[1000]; /*please mind the length*/
extern void* ptr_to_var2;
printf("var1 addr is %p, var2 addr is %p\n", (void*)&var1, ptr_to_var2);

このコードは生成します

var1 アドレスは 0xa11b00、var2 アドレスは 0xa11e00

ご覧のとおり、var1 はアドレス 0xa11ee8 に配置され、var2 のヘッドは var1 メモリ内にあります。私は何を間違っていますか?静的ライブラリでグローバル変数を使用する際に制限はありますか? これらの変数は、各ライブラリ内の多数のファイルで使用されているため、静的として定義することはできません。これらの変数を動的にするのは大変な作業です (そのような変数は数十あります)。

PS もちろん、ptr_to_var2 は初期化されます。本当に何が起こっているのか

<lib3>
void* ptr_to_var2;

<lib2>
#include "hdr_with_my_struct_name_definition.h"
my_struct_name var2[5];
extern void* ptr_to_var2;

int func2(){
   ptr_to_var2=(void*)&var2;
   var2[0].fld1=12345;
   return 1;
}

<lib 1>
#include "hdr_with_my_struct_name_definition.h"
char var1[1000];
extern void* ptr_to_var2;

int func1(){
   my_struct_name *temp_var_2=(my_struct_name*)ptr_to_var2;
   printf("%d", temp_var_2[0].fld1);
   memset(var1, '\0', sizeof(var1);
   printf("%d", temp_var_2[0].fld1);
   return 1;
}

<binary>

main(){
   func2();
   func1();
   return;
}

このすべてが 12345 0 を返します

4

2 に答える 2

1
printf("var1 addr is %p, var2 addr is %p\n", (void*)&var1, ptr_to_var2);

ptr_to_var2これでは、実際にはアドレスではない値を出力しようとしています。この変数はまだ初期化されていないため、その値はランダムです。

#include<stdio.h>

char v[1000];

void *p1;

int main() {

    printf ("var1 %p, var2 %p  &var2 %p\n", &v[0], p1, &p1);

    return 0;
}

与える:

var1 0x601040, var2 (nil)  &var2 0x601428
于 2012-10-03T10:07:17.917 に答える
0

このextern句を使用すると、リンク時にそのシンボルを解決するようにコンパイラに指示します。リンク後、バイナリファイルには。という名前のシンボルが1つだけ表示されますptr_to_var。もちろん、どこかで初期化されることを保証する必要があります。貼り付けたコードでは、初期化されているかどうかわかりません。あなたはしなかったようですが。

ちなみに、nmライブラリに作ってみてください。未定義(大文字のu)として指定したシンボルが表示されますextern。ただし、実際に定義されている(つまり、extern句なしで宣言されている)ライブラリまたはオブジェクトファイルを除きます。

于 2012-10-03T10:22:15.803 に答える