1. 程式人生 > >C語言中全域性變數初始化的重要性!!!

C語言中全域性變數初始化的重要性!!!

在C語言裡,全域性變數如果不初始化的話,預設為0,也就是說在全域性空間裡:

  int x =0; 跟 int x; 的效果看起來是一樣的。但其實這裡面的差別很大,強烈建議大家所有的全域性變數都要初始化,他們的主要差別如下:

  編譯器在編譯的時候針對這兩種情況會產生兩種符號放在目標檔案的符號表中,對於初始化的,叫強符號,未初始化的,叫弱符號。

  聯結器在連線目標檔案的時候,如果遇到兩個重名符號,會有以下處理規則:

  1、如果有多個重名的強符號,則報錯。

  2、如果有一個強符號,多個弱符號,則以強符號為準。

  3、如果沒有強符號,但有多個重名的弱符號,則任選一個弱符號。

  基於以上規則看下面的程式:(編譯器為gcc 3.4.6, VC下結果不一樣)


   main.c

       #include <stdio.h>
  int x = 1;
  void foo(void);
  int main(int argc, char* argv[])
  {
  printf("x1:%d\n", x);
  foo();
  printf("x2:%d\n", x);
  return 0;
  }

--------

var.c
  int x = 0;
  void foo(void)
  {
  x = 2;
  }

  因為兩個檔案裡面的x都被初始化了,所以編譯出來的兩個目標檔案裡x都是強符號,連線的時候會報錯:

  multiple definition of `x'

  符合規則1。

  把var.c裡面的int x = 0;改成 int x; 不做初始化,編譯、連線無任何警告,執行結果為:

  x:1

  x:2

  說明連線的時候以main.c中的x為準,foo函式修改的是main.c中定義的x。符合規則2。

  把main.c中的初始化也去掉,改成 int x; 編譯、連線仍然很順利,執行結果為:

  x:0

  x:2

  說明main函式和foo函式修改的是同一個x,聯結器自己選擇了一個x,符合規則3.

  大部分情況下,我們不希望聯結器為我們做決定,所以我不是很認同後兩個規則,至少應該給個警告,而不應該安靜地通過。

  也許寫var.c的人根本不知道main.c裡面也有一個x呢,foo函式的本意也許並不是要修改main.c中的x。因為這種問題引起的bug會很難查。

  所以我們要儘量把全域性變數初始化,對於不想給別的檔案引用的變數,也儘量用static修飾。

  除了連線時的表現不一樣外,未初始化的符號在目標檔案的bss段中,而初始化的符號在data段中。