外部鏈接和內部鏈接 參見 https://blog.csdn.net/xiexievv/article/details/8487373 ,非常詳細!
補充1: 不完全聲明
struct s;
union u;
char str[];
編譯器不知道這種類型該佔幾個字節的存儲空間!!
具有不完全類型的變量可以通過多次聲明組合成一個完全類型,比如數組 str 聲明兩次:
char str[];
char str[10];
當編譯器碰到第一個聲明時,認爲 str 是一個不完全類型,碰到第二個聲明時 str 就組合成完全類型了,如果編譯器處理到程序文件的末尾
仍然無法把 str 組合成一個完全類型,就會報錯。讀者可能會想,這個語法有什麼用呢?爲何不在第一次聲明時就把 str 聲明成完全類型?有些情況下這麼做有一定的理由,比如第一個聲明是寫在頭文件裏的,第二個聲明寫在 .c 文件裏,這樣如果要改數組長度,只改 .c 文件就行了,頭文件可以不用改。
補充2: int i;
以下:
int i;
int i;
gcc 可以編譯通過:int i;
沒有明確的初始化操作,屬於 臨時性定義(tentative definition) 可以在程序中發生多次發生,但是最後只留一個單獨的實體 。
g++不能編譯通過:int i;
屬於 聲明性定義 ,聲明的同時定義了該變量,不能重複定義變量。 C++ 決不允許重複執行相同的定義或聲明,例如類的定義、struct與enum所定義的自定義類型,所以C++裏面有大量的條件編譯語句(#if
、#ifdef
、#elif
、#else
、#ifndef
、#endif
、#define
、#undef
)。但是類型定義typedef
可以重複。
gcc:
int i1 = 1; // definition, external linkage (gcc,標準的外部鏈接定義)
static int i2 = 2; // definition, internal linkage
extern int i3 = 3; // definition, external linkage (gcc,不標準的外部鏈接定義,應該去掉extern,否則被警告)
int i4; // tentative definition, external linkage
static int i5; // tentative definition, internal linkage
int i1; // valid tentative definition, refers to previous(gcc,允許先定義後臨時性定義)
int i2; // 6.2.2 renders undefined, linkage disagreement (gcc,不允許先內部鏈接定義,再外部鏈接臨時性定義)
int i3; // valid tentative definition, refers to previous
int i4; // valid tentative definition, refers to previous
int i5; // 6.2.2 renders undefined, linkage disagreement(gcc,不允許先內部鏈接臨時性定義,再外部鏈接臨時性定義)
extern int i1; // refers to previous, whose linkage is external
extern int i2; // refers to previous, whose linkage is internal
extern int i3; // refers to previous, whose linkage is external
extern int i4; // refers to previous, whose linkage is external
extern int i5; // refers to previous, whose linkage is internal