[英]What is wrong with this C program using extern keyword?
我想在main.c中使用來自foo.c的變量a,我寫道:
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)
為什么?
的類型的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”。 a[n]
等於*(a + n)
,即將地址a
前進n
單位,然后取消引用它以獲得內容。 因此, a[0]
相當於*0x100
,它返回0x100的內容,即“3”。 當a
是指針時 ,
a
是在所提供的地址的內容。 實際上這是常態,數組類型是一種特殊情況。 因此,當您打印a
,您將獲得該地址的內容,即“3”。 a[n]
仍為*(a + n)
。 因此, a[0]
相當於*3
,這會導致分段錯誤,因為地址“3”無效。 您必須對跨不同翻譯單元聲明的對象使用一致類型。
給定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*
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.