C 語言聲明與定義不一致導致的問題

來源:文萃谷 1.33W

我們在寫代碼的時候,往往只注意函數的實現,對函數的聲明重視不足。下面是小編為大家帶來的C 語言聲明與定義不一致導致的問題,歡迎閲讀

C 語言聲明與定義不一致導致的問題
  C 語言聲明與定義不一致導致的問題

最近項目代碼需要從mips平台移植到x86平台,這是公司產品第一次採用x86平台。之前項目很緊,所以很多代碼都沒有考慮移植性問題,因此移植的時候遇到了不少問題。前幾天才解決了位序(也叫比特序,與字節序不同)問題,今天又遇到了一個比較隱蔽的C語言問題,在這裏記錄一下,告誡自己,也告誡各位同行,避免犯這樣的錯誤。至於位序問題,以後應該會再另寫一篇文章來説明。

原本在mips平台上運行良好的代碼,移植到了x86平台,結果卻不對了,我們仔細分析了代碼,沒發現什麼可疑的地方,而且我之前為了優化那段代碼,單獨把那段代碼抽出來測試過。我抽出來的代碼在兩個平台裏得出的都是一樣的.結果。我對比了代碼,實現的地方沒有任何改動,照理説不應該出現這種情況的。不過根據打印出來的值,我注意到了一種情況,在x86平台裏的結果值只有16位,但在mips平台裏的結果值有32位,並且低16位的值與x86平台下的值一樣。最後,我查看了聲明該函數的頭文件,才發現頭文件裏函數的聲明與C文件裏的實現返回值不一致!

問題可以簡化成下面的代碼:

//crc.c

//注意,此處沒有包含crc.h這個頭文件!

unsigned int get_crc(void)

{

return 0x12345678;

}

//crc.h

unsigned short get_crc(void);

//main.c

#include

#include "crc.h"

int main(int argc, char *argv[])

{

unsigned int crc = get_crc();

printf("crc:%x", crc);

return 0;

}

編譯執行: gcc -Wall -o test main.c crc.c //好吧,-Wall也沒辦法報錯

在x86平台下輸出:5678

我又分別在mips平台和powerpc平台下編譯執行了這段代碼,同樣沒警告或者報錯。在mips平台下輸出:12345678,在powerpc平台下輸出:12345678

在簡化的代碼裏,大家很容易就能看出是get_crc這個函數的聲明和定義(實現)不一致導致的問題,但在龐大的項目文件裏,可能就沒那麼容易看出問題所在了。

我們在寫代碼的時候,往往只注意函數的實現,對函數的聲明重視不足。在Linux平台下,我們喜歡用cscope+ctags+vim來寫代碼,修改或者瀏覽代碼的時候也喜歡跳到函數定義處,變量聲明處,卻很少關注函數聲明,導致修改代碼之後聲明和定義不一致的情形。

這並不只是程序新手才會出現的問題,工作幾年的程序員也可能會犯這樣的錯誤,出現問題的這段代碼,就是出自一個已經工作了四年的同事之手。

也正是在這個時候,我才發現,我們之前的代碼是有問題的,只是所謂的“得到了正確的結果”。

我起先認為對於這種情況,是個編譯器未定義形為,不同gcc版本對這種情況的處理可能不一樣,但我進行了一些測試,發現情況比我想象中的複雜。在powerpc平台,gcc版本是3.3.x,mips平台,gcc版本是4.3.x,在x86平台,有兩個版本的編譯器,分別為4.1.x(centos),4,6.x(ubuntu)執行情況是mips平台和powerpc平台一樣,都是12345678,x86平台下均為5678。mips和powerpc都是大端,x86是小端,至令我沒辦法判斷真正的問題在哪,是編譯器版本原因還是與大小端有那麼點關係。還望知道的朋友不吝賜教。

此外,我還測試了對於變量的情況,發現對於變量的處理,各個gcc版本不同平台都是一致的,當然,由於大小端的關係,輸出結果會不同。大家有興趣可以試一下。

説了那麼多,只是想説明這個隱蔽的錯誤大家一不小心就很容易犯,而且後果也比較嚴重,得找到方法避免。解決辦法很簡單,那就是通過把函數聲明(原型)放在頭文件中,而函數定義則放在另一個包含了該頭文件的源文件中。這樣編譯器就能發現不一致的情況從而報錯提醒我們。這個問題在《C專家編程》8.5節有論述。

熱門標籤