- 相關(guān)推薦
C 語(yǔ)言聲明與定義不一致導(dǎo)致的問(wèn)題
我們?cè)趯?xiě)代碼的時(shí)候,往往只注意函數(shù)的實(shí)現(xiàn),對(duì)函數(shù)的聲明重視不足。下面是小編為大家?guī)?lái)的C 語(yǔ)言聲明與定義不一致導(dǎo)致的問(wèn)題,歡迎閱讀。
C 語(yǔ)言聲明與定義不一致導(dǎo)致的問(wèn)題
最近項(xiàng)目代碼需要從mips平臺(tái)移植到x86平臺(tái),這是公司產(chǎn)品第一次采用x86平臺(tái)。之前項(xiàng)目很緊,所以很多代碼都沒(méi)有考慮移植性問(wèn)題,因此移植的時(shí)候遇到了不少問(wèn)題。前幾天才解決了位序(也叫比特序,與字節(jié)序不同)問(wèn)題,今天又遇到了一個(gè)比較隱蔽的C語(yǔ)言問(wèn)題,在這里記錄一下,告誡自己,也告誡各位同行,避免犯這樣的錯(cuò)誤。至于位序問(wèn)題,以后應(yīng)該會(huì)再另寫(xiě)一篇文章來(lái)說(shuō)明。
原本在mips平臺(tái)上運(yùn)行良好的代碼,移植到了x86平臺(tái),結(jié)果卻不對(duì)了,我們仔細(xì)分析了代碼,沒(méi)發(fā)現(xiàn)什么可疑的地方,而且我之前為了優(yōu)化那段代碼,單獨(dú)把那段代碼抽出來(lái)測(cè)試過(guò)。我抽出來(lái)的代碼在兩個(gè)平臺(tái)里得出的都是一樣的結(jié)果。我對(duì)比了代碼,實(shí)現(xiàn)的地方?jīng)]有任何改動(dòng),照理說(shuō)不應(yīng)該出現(xiàn)這種情況的。不過(guò)根據(jù)打印出來(lái)的值,我注意到了一種情況,在x86平臺(tái)里的結(jié)果值只有16位,但在mips平臺(tái)里的結(jié)果值有32位,并且低16位的值與x86平臺(tái)下的值一樣。最后,我查看了聲明該函數(shù)的頭文件,才發(fā)現(xiàn)頭文件里函數(shù)的聲明與C文件里的實(shí)現(xiàn)返回值不一致!
問(wèn)題可以簡(jiǎn)化成下面的代碼:
//crc.c
//注意,此處沒(méi)有包含crc.h這個(gè)頭文件!
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;
}
編譯執(zhí)行: gcc -Wall -o test main.c crc.c //好吧,-Wall也沒(méi)辦法報(bào)錯(cuò)
在x86平臺(tái)下輸出:5678
我又分別在mips平臺(tái)和powerpc平臺(tái)下編譯執(zhí)行了這段代碼,同樣沒(méi)警告或者報(bào)錯(cuò)。在mips平臺(tái)下輸出:12345678,在powerpc平臺(tái)下輸出:12345678
在簡(jiǎn)化的代碼里,大家很容易就能看出是get_crc這個(gè)函數(shù)的聲明和定義(實(shí)現(xiàn))不一致導(dǎo)致的問(wèn)題,但在龐大的項(xiàng)目文件里,可能就沒(méi)那么容易看出問(wèn)題所在了。
我們?cè)趯?xiě)代碼的時(shí)候,往往只注意函數(shù)的實(shí)現(xiàn),對(duì)函數(shù)的聲明重視不足。在Linux平臺(tái)下,我們喜歡用cscope+ctags+vim來(lái)寫(xiě)代碼,修改或者瀏覽代碼的時(shí)候也喜歡跳到函數(shù)定義處,變量聲明處,卻很少關(guān)注函數(shù)聲明,導(dǎo)致修改代碼之后聲明和定義不一致的情形。
這并不只是程序新手才會(huì)出現(xiàn)的問(wèn)題,工作幾年的程序員也可能會(huì)犯這樣的錯(cuò)誤,出現(xiàn)問(wèn)題的這段代碼,就是出自一個(gè)已經(jīng)工作了四年的`同事之手。
也正是在這個(gè)時(shí)候,我才發(fā)現(xiàn),我們之前的代碼是有問(wèn)題的,只是所謂的“得到了正確的結(jié)果”。
我起先認(rèn)為對(duì)于這種情況,是個(gè)編譯器未定義形為,不同gcc版本對(duì)這種情況的處理可能不一樣,但我進(jìn)行了一些測(cè)試,發(fā)現(xiàn)情況比我想象中的復(fù)雜。在powerpc平臺(tái),gcc版本是3.3.x,mips平臺(tái),gcc版本是4.3.x,在x86平臺(tái),有兩個(gè)版本的編譯器,分別為4.1.x(centos),4,6.x(ubuntu)執(zhí)行情況是mips平臺(tái)和powerpc平臺(tái)一樣,都是12345678,x86平臺(tái)下均為5678。mips和powerpc都是大端,x86是小端,至令我沒(méi)辦法判斷真正的問(wèn)題在哪,是編譯器版本原因還是與大小端有那么點(diǎn)關(guān)系。還望知道的朋友不吝賜教。
此外,我還測(cè)試了對(duì)于變量的情況,發(fā)現(xiàn)對(duì)于變量的處理,各個(gè)gcc版本不同平臺(tái)都是一致的,當(dāng)然,由于大小端的關(guān)系,輸出結(jié)果會(huì)不同。大家有興趣可以試一下。
說(shuō)了那么多,只是想說(shuō)明這個(gè)隱蔽的錯(cuò)誤大家一不小心就很容易犯,而且后果也比較嚴(yán)重,得找到方法避免。解決辦法很簡(jiǎn)單,那就是通過(guò)把函數(shù)聲明(原型)放在頭文件中,而函數(shù)定義則放在另一個(gè)包含了該頭文件的源文件中。這樣編譯器就能發(fā)現(xiàn)不一致的情況從而報(bào)錯(cuò)提醒我們。這個(gè)問(wèn)題在《C專(zhuān)家編程》8.5節(jié)有論述。
【C 語(yǔ)言聲明與定義不一致導(dǎo)致的問(wèn)題】相關(guān)文章:
C語(yǔ)言宏定義07-01
C語(yǔ)言函數(shù)的定義07-13
C語(yǔ)言變量定義07-29
C語(yǔ)言變量的定義與使用09-05
C語(yǔ)言宏定義技巧09-03
C語(yǔ)言的宏定義分析09-10
C語(yǔ)言數(shù)組的定義及引用08-05
C語(yǔ)言聲明的語(yǔ)法04-26