C語言全局變量的定義與聲明


    C語言中全局變量的定義與聲明困擾着許多C語言初學者。本文講述了全局變量定義與聲明的用法,而且本為也將闡述這種用法的內在原理。我們先從兩個錯誤例子引入,以下兩個例程都在vc6.0平台上測試。

兩種錯誤例程

1.unresolved external symbol

例子包含兩個C文件(test.c)和(first.c)和一個頭文件(test.h)。下邊具體展示下它們的代碼。

test.h內容

#ifndef _TEST_H
#define _TEST_H
 
extern int count;   

#endif

test.c內容

#include <stdio.h>
#include "test.h"
extern void Fis_Cal(void);
void main(void)
{
 Fis_Cal();
  printf("the present value of count is %d\n",count);
}

first.c內容

#include <stdio.h>
#include "test.h"
void Fis_Cal(void)
{
 printf("the last value of count is %d\n",count);
 count = 1;
}

錯誤分析:test.h頭文件中聲明了全局變量count,但是在兩個C文件中都沒有對count進行定義,所以才會出現unresolved external symbol。

一種解決方法:隨便在兩個C文件中加入一句“int count;”就OK了。例如我們加到test.c中,代碼如下。 

#include <stdio.h>
#include "test.h"
extern void Fis_Cal(void);
int count;
void main(void)
{
 Fis_Cal();
 printf("the present value of count is %d\n",count);
}

說明:加入的“int count;”就是對count的定義,默認的將其初始化為0。

結論:這種錯誤原因是“只聲明未定義”。

2.multiply defined symbols found

還是如此,三個文件。但是,兩個C文件與例程一中的文件一樣,改動的只是頭文件。

test.h內容

#ifndef _TEST_H
#define _TEST_H
 
int count; 

#endif

可以看到,與例程一僅僅差了一個“extern”關鍵詞。

錯誤分析:test.h頭文件中定義了全局變量count,但是在兩個C文件都通過“#include "test.h"”這句話對“int count;”進行了引用,所以造成了重復定義的錯誤。

一種解決方法:添加一個“first.h”的頭文件,並且更改first.c的內容,具體更改如下。

first.h內容

#ifndef _FIRST_H
#define _FIRST_H

extern int count;

#endif

first.c內容

#include <stdio.h>
#include "first.h"
void Fis_Cal(void)
{
 printf("the last value of count is %d\n",count);
 count = 1;
}

說明:經過這樣的修改,原來的test.c中就包含了count的定義,而first.c中就包含了對count的聲明,重復定義錯誤就得到解決。

結論:這種錯誤原因是“多個C程序都包含了定義全局變量的頭文件”。 

原理分析

    我認為“int count;”是對全局變量的定義,而“extern int count”是對全局變量的聲明,目的是讓其他文件也使用這個全局變量。下邊我們來挖掘全局變量的定義與聲明的內涵。

    全局變量要么初始化(非零),要么沒有初始化(為零)。非零時存儲在程序中的data段,零時存儲在程序的bss段。這談了程序(.bin或者.hex)的結構。我再講一下程序的啟動,程序在啟動(boot)過程中,通常都會運行一個叫bootloader的引導程序,這個引導程序干了很多事情,其中有一最重要的任務就是把程序(test段和rodata段)拷貝到內存,還包括data段的拷貝和bss段初始化。我們着重講一下data段的拷貝和bss段初始化。

    我們的編譯器會為我們定義的全局變量分配內存(地址),而且給我們的全局變量賦初值(寫內存或清零),以后我們的程序就會根據需要來讀這個全局變量(地址)或者修改這個全局變量(寫內存)。初值為零時就在bss段,這個段初始化代碼會將這部分清零。初值非零時,初始化代碼會將全局變量的初值拷貝到data段。

    那么,顯然全局變量的初值只有一個。我們程序中的全局變量的定義就是對全局變量分配內存並賦初值。而全局變量的聲明是為了跨文件使用全局變量的需要,通過"extern"關鍵詞來將全局變量引出。 

順便說一下C語言的存儲類說明符,這能幫助我們加深理解。

C語言的存儲類說明符

     Auto 只在塊內變量聲明中被允許, 表示變量具有本地生存期。

     Extern 出現在頂層或塊的外部變量函數與變量聲明中,表示聲明的對象具有靜態生存期, 連接程序知道其名字。

    Static 可以放在函數與變量聲明中,在函數定義時,只用於指定函數名,而不將函數導出到鏈接程序,在函數聲明中,表示其后邊會有定義聲明的函數,存儲類型static.在數據聲明中,總是表示定義的聲明不導出到連接程序關鍵字。

一種更好的聲明與定義方式

test.h內容 

#ifndef _TEST_H
#define _TEST_H
 
#ifdef GLOBALS
int count;
#else
extern int count;
#endif 

#endif

test.c內容

#define GLOBALS
#include <stdio.h>
#include "test.h"
extern void Fis_Cal(void);
void main(void)
{
 Fis_Cal();
 printf("the present value of count is %d\n",count);
}

first.c內容

#include <stdio.h>
#include "test.h"
void Fis_Cal(void)
{
 printf("the last value of count is %d\n",count);
 count = 1;
}

說明:這種方法可以只定義一個頭文件實現在不同C文件中分別實現定義與聲明。“#define GLOBALS”只在當前定義的test.c文件中有效,所以在test.c中#include "test.h"預處理后,加入的是int count,而first.c中加入的"extern int count;"。其實還有一種書寫方法,也能實現這個效果。

test.h內容 

#ifndef _TEST_H
#define _TEST_H
 
#ifdef GLOBALS
#define EXT
#else
#define EXT extern
#endif

EXT int count;

#endif 。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM