2012-06-23 26 views
5

我想在main.c中使用變量來自foo.c的,和我寫的:這個使用extern關鍵字的C程序有什麼問題?

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位操作系統嗎? –

+0

@PaulR I使用32位ubuntu 12.04 –

回答

8

a的類型是int[2],而不是int*。與

extern int a[2]; 

再次嘗試C編譯器跨源文件不能鍵入檢查。因此,當你說int* a時,編譯器會假設你說的是實話,使用指針語義,並且不會發出任何編譯器錯誤。

數組和指針之間存在細微差別。我們假設一個32位系統。然後的內容「a」將被分佈是這樣的:

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

a陣列

  • 表達a的值將被轉換爲的a地址。因此,當您打印a時,您將獲得其地址,即「0x100」。
  • C中的操作a[n]相當於*(a + n),即將地址a提前n個單位,然後將其解引用以獲取內容。因此,a[0]相當於*0x100,它返回0x100處的內容,即「3」。

a指針

  • 的的a 「值」 是在所提供的地址的內容。實際上這是規範,數組類型是一個特例。因此,當您打印a時,您將收到該地址的內容,即「3」。
  • 操作a[n]仍然是*(a + n)。因此,a[0]相當於*3,由於地址「3」無效,導致分段錯誤。
+0

但是'int a [2]'也是指針,除非編譯器知道它在編譯時的大小。或者我的理解在這裏錯了? –

+0

但是這個程序可以編譯成功,沒有錯誤。 –

+4

@NiklasR:否'int a [2]'不是一個指針,它是一個數組。 'extern int a [];'也可以工作,所以差異不是已知的大小。 –

1

您必須使用一致的類型來爲跨不同翻譯單元聲明的對象。

鑑於int a[] = {2, 3};,聲明extern int a[];extern int a[2]中的任一個;將是兼容的,而extern int *a;不會作爲指針和數組是完全獨立的類型。

的唯一特別陣列是當一個陣列的名稱將出現在任何表達式中除作爲操作數到(一元&)或sizeof,它們被自動轉換爲一個指向其第一「的地址」元件。這提供了數組和指針之間的語法兼容性,但它們不是相同的類型。

考慮這兩個函數的評論示例。請注意,表達式a被轉換爲指向第一個函數的第二個(技術上第三個)printf中的第一個元素的指針,但不是在第一個printf中,它是&的操作數。

#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]) 
} 

請注意,我用%p打印指針和顯式轉換爲void*