1. 程式人生 > >C語言定義和宣告區別

C語言定義和宣告區別

1. 變數的定義和宣告

C語言定義和宣告分為變數的定義和宣告和函式的定義和宣告。由於,函式是具有全域性外部特性,並且函式的定義和宣告區別是很明顯的。其宣告需要返回值型別,函式名和引數列表。而函式的定義需要函式體。所以,很容易區別函式的宣告和定義。對於變數的宣告和定義,就不是那麼明顯。通常變數定義和宣告的區別是有沒有為變數分配記憶體。如果為變數分配記憶體就是定義,否則就是宣告。變數宣告可以出現多次,但定義只能出現一次。

2. 強符號和弱符號

強符號:函式和初始化的全域性變數稱為強符號。

弱符號:  未初始化的全域性變數稱為弱符號。

在程式中,強符號只能出現1次,弱符號會出現多次。如果存在一個強符號和多個弱符號,gcc會選擇強符號。如果存在多個弱符號,會選擇其中一個弱符號作為定義,並分配記憶體。

3. 例項

例項1:多個強符號

三個檔案test11.h, test11.c和test22.c,具體如下:

test11.h:

#ifndef _TEST1_H
#define _TEST1_H
#include <stdio.h>
int i=1; //此處i是定義,是強符號
void printmsg();
#endif

test11.c

#include "test11.h"
void printmsg(){
  printf("i=%d\n",i);
}

test22.c

#include "test11.h"
int main(){
 printmsg();
 return 0;
}

編譯結果:

test11.o:(.data+0x0): multiple definition of `i'
test22.o:(.data+0x0): first defined here

由於出現了多個強符號,所以連結時i重定義了。


例項2:多個弱符號和1個強符號

test11.h

#ifndef _TEST1_H
#define _TEST1_H
#include <stdio.h>
int i;
int i;
void printmsg();
#endif
此處int i,準確來說是定義性宣告,既是定義也是宣告,但沒有初始化,稱為弱符號。


test11.c

#include "test11.h"
void printmsg(){
  printf("i=%d\n",i);
}

test22.c

#include "test11.h"
int i=10;
int main(){
 printmsg();
 return 0;
}

在test33.c對i進行了定義,為強符號。

執行結果:

i=10

當存在多個弱符號和1個強符號時,gcc會選擇強符號,能夠正常的編譯和執行。


例項3:多個弱符號

test11.h

#ifndef _TEST1_H
#define _TEST1_H
#include <stdio.h>
int i;
int i;
void printmsg();
#endif
此處int i,準確來說是定義性宣告,既是定義也是宣告,但沒有初始化,稱為弱符號。


test11.c

#include "test11.h"
void printmsg(){
  printf("i=%d\n",i);
}

test22.c
#include "test11.h"
 int main(){
 printmsg();
 return 0;
}

去掉test22.c中的i定義,此時只有多個弱符號。

執行結果:

i=0;

當存在多個弱符號時,gcc會選擇其中一個弱符號作為定義。由於i未初始化,所以儲存在.bss段上,關於變數儲存位置,將在以後文章作詳細介紹。.bss段變數用0進行填充。

注意: 當GCC編譯器看到 int i時,在連結的時候,搜尋源程式,如果定義變數i(有初始值),就把此處的i看成是宣告。如果別處沒有定義,就為此處的i分配空間,即當作定義。

所以: i的轉換過程為:定義性宣告((或稱為暫定義)->定義。


4. 結構體的定義和宣告

struct A{

  int i;

 int j;

};

稱為型別定義,和變數定義完全不同。即定義一種新的資料型別,類似int型別。如果GCC在編譯時檢查出多個結構體定義,就會報重定義錯誤。即某個程式出現了:

struct A{};

struct A{};

在連結時,如果多個檔案中存在結構體定義,則不會報錯,gcc在連結時只檢查符號,這裡的符號指的是變數和函式之類的符號,而不是型別符號。不會檢查語法。所以在多個檔案中出現結構體定義沒有問題。

struct A A1;

A1稱為結構體變數宣告,和普通變數類似。

總結:

(1)變數定義和宣告的本質區別:是否分配記憶體。

(2)區域性變數不能多次宣告,即在同一程式碼塊(即同一作用域)的區域性變數不可多次宣告。區域性變數不能出現 int i; int i;

(3)需要強調的是,不要在標頭檔案定義全域性變數,容易引起重定義。