2012-06-23 5 views
5

私はmain.cの中のfoo.cから変数aを使用したい、と私は書く:このCプログラムでexternキーワードを使用すると何が問題になりますか?

foo.c 
#include <stdio.h> 

int a[] = {3, 2}; 

void foo() 
{ 
    printf("foo\taddress of a:%x\n", a); 
    printf("foo\tvalue of a[0]:%x\n", a[0]); 
} 

main.c 
#include <stdio.h> 

extern int *a; 

int main(void) 
{ 
    foo(); 
    printf("main\taddress of a : %x\n", a); 
    printf("main\tvalue of a[0] : %x\n", a[0]); 

    return 0; 
} 

と結果出力:

foo address of a:804a014 
foo value of a[0]:3 
main address of a : 3 
Segmentation fault (core dumped) 

なぜですか?

+0

64ビットOSをお使いですか? –

+0

@PaulR私は32ビットのubuntuを使用しています12.04 –

答えて

8

aのタイプは、int[2]であり、int*ではありません。 Cコンパイラは、ソースファイル渡ってチェックを入力することはできません

extern int a[2]; 

で再試行してください。したがって、int* aと言うとき、コンパイラはあなたが真実を伝えていると仮定し、ポインタの意味を使用し、コンパイラエラーを発行しません。

配列とポインタには微妙な違いがあります。 32ビットシステムを想定しましょう。その後の内容は「」のように配布される:式a

 
    a 
0x100  0x104  0x108 ← address 
    +-----------+----------+ 
    |   3 |  2 | ← content 
    +-----------+----------+ 

a配列ある、

  • aのアドレスに変換されています。したがって、aを印刷すると、そのアドレス、つまり「0x100」が取得されます。
  • Cの操作a[n]は、*(a + n)に相当します。つまり、アドレスan単位で進めてから、逆参照して内容を取得します。したがって、a[0]*0x100に相当し、0x100のコンテンツ、つまり「3」を返します。

aポインタある、

  • aの "値" が提供されたアドレスのコンテンツです。実際これが標準であり、配列タイプは特殊なケースです。したがって、aを印刷すると、そのアドレスのコンテンツ(「3」)が取得されます。
  • 操作a[n]はまだ*(a + n)です。したがって、a[0]*3と等価であり、アドレス「3」が無効であるためセグメンテーションフォルトが発生します。
+0

しかし、 'int [2]'もコンパイラがコンパイル時にサイズを知っていることを除いて、ポインタです。それとも私の理解は間違っていますか? –

+0

しかし、このプログラムは正常にコンパイルできますが、エラーはありません。 –

+4

@NiklasR:いいえ 'int a [2]'はポインタではなく、配列です。 'extern int a [];'も同様に動作するので、その違いは既知のサイズではありません。 –

1

異なる翻訳単位で宣言されたオブジェクトに一貫したタイプを使用する必要があります。

extern int a[];またはextern int a[2]のいずれかの宣言の場合、int a[] = {2, 3};が指定されています。互換性がありますが、extern int *a;はポインタと配列ではできません。配列は完全に別の型です。

配列の特別なことは、配列の名前が "address of"(単項位&)またはsizeofのオペランド以外の任意の式のコンテキストに現れるとき、配列の最初のものへのポインタに自動的に変換されます素子。これは、配列とポインタの間の構文の互換性を提供するものですが、同じ型ではありません。

コメント付きの例として、これらの2つの機能を検討してください。式aは、最初の関数の2番目の(そして3番目の)printfの最初の要素へのポインタに変換されますが、最初のprintfではなく、&のオペランドです。私はポインタを印刷する%pを使用して明示的にキャストvoid*

#include <stdio.h> 

void print_array_info(void) 
{ 
    extern int a[]; 
    printf("address of a: %p\n", (void*) &a); // prints address of a 
    printf(" converted a: %p\n", (void*) a); // prints address of a[0] 
    printf("value of a[0]: %x\n", a[0]);   // prints value of a 
} 

void print_pointer_info(void) { 
    extern int a[]; 
    int *b = a; // == &a[0] 

    printf("address of b: %p\n", (void*) &b); // prints address of b 
    printf(" value of b: %p\n", (void*) b); // prints value of b (== &a[0]) 
    printf("value of b[0]: %x\n", b[0]);  // prints value of b[0] (== a[0]) 
} 

注意。

関連する問題