博客:blog.focus-linux.net linuxfocus.blog.chinaunix.net
======================================================
今天這個主題很簡單。但是這麼一個初級問題,居然真正發生在我的周圍。
前幾天幫助同事檢查一個問題。他這樣描述該現象:他定義了一個全局變量,然後調用一個函數F修改了該全局變量,但是退出函數時該全局變量的值又被改了。我到他的調試環境中,先查看了一下現象。問題重現了。—— 我一直認爲,所有能夠重現的問題都不是問題。只要能夠重現,就一定可以修正。
對於這一問題,我的第一反應是競爭引起的。於是我首先使用GDB的set scheduler-locking on,保證其它線程處於停止狀態,避免競爭。又試了一次,問題還是存在。在函數退出的時候,打印了一下當時的值。然後退出,再次打印,發現其值變爲了初始值。感覺確實有點奇怪。於是看了看他的代碼,一看該全局變量定義在頭文件中static int g_variable = 0。看到這裏,儘管我不知道其它代碼是怎麼寫的。我就想到了問題的原因。這裏的全局變量g_variable肯定有兩份。函數F和調用者一定在不同的文件中,它們都include了這個頭文件。結果在函數F中修改了一個g_variable,而調用者中使用和查看的是另一個g_variable。解決方法是,去一個c文件中定義這個全局變量,然後到頭文件中聲明。
雖然我很快的解決了這個問題。但是我卻想,這個問題真的是一個很初級的問題。而我這位同事已經是一名senior的開發人員了。爲什麼還會犯這種錯誤呢?這裏我對事不對人。主要的原因還是對於編程的基礎沒有理解。頭文件中不要定義全局變量,看似是一條死的規則。其實只要真正領會什麼是頭文件,頭文件是如何include到.c源文件中的。這條規則根本不需要記憶,而是一種理解。這樣會自然的就會寫出正確的代碼,而不會犯這樣的錯誤。
說到這裏,簡單說一下頭文件的知識。頭文件的作用,主要是用於聲明變量,函數等等,然後可以被多個源文件引用。其實我認爲其根本目的,一是爲了代碼的整齊,更重要是爲了消除重複的代碼。因爲多個源文件都要相同的聲明,這時就可以用一行include 頭文件來解決。而include,在預編譯階段,實際上是將頭文件中所有的代碼都插入到include的位置。真正理解了這個過程,肯定不會犯本文中的這個錯誤。
頭文件:
//
// comment.h
#ifndef comment_h
#define comment_h
static int ss = 100;
extern int F();
#endif
F()函數所在文件
//
// comment.c
//
#include <stdio.h>
#include "comment.h"
int F()
{
ss = 88;
printf("%s ss = %d \n",__FUNCTION__,ss);
return ss;
}
main.c 所在文件:
//
// main.c
//
#include <stdlib.h>
#include <stdio.h>
#include "comment.h"
int main()
{
printf("[0]--->[%d]\n",ss);
F();
printf("[1]--->[%d]\n",ss);
return 0;
}
輸出結果:
[0]--->[100]
F ss = 88
[1]--->[100]