在程式裡頭經常會用到整數之間的大小比較,但是其中潛在的危險卻往往被忽略了。例如乙個記憶體拷貝函式:
void memcpy(void *pto,void *pfrom,size_t size)
} 這個函式正確嗎?如果你認為它永遠都不可能跳出那個該死的迴圈就對了。size_t是乙個無符號整數型別(vc6.0: typedef unsigned int
size_t,vc7.1: typedef unsigned __int64 size_t),所以--size得到的結果也是同樣型別,而這樣乙個型別的值永遠也不可能小於0!那我
們嘗試著改進它:
void memcpy(void *pto,void *pfrom,size_t size)
} 這個版本中更改了迴圈條件,使得當size等於0的時候迴圈結束。危險消除了嗎?嗯,消除了大部分,但是還存在著乙個令人不愉快的地
方。如果有乙個int型別的變數len,用它做size的實參來呼叫memcpy,又假設碰巧len的值小於0,那麼會出現什麼結果呢?size接收到了乙個
負值,但因為它本身是無符號型的,所以它會把這個負值解釋成為無符號型整數,那必然是個正值,如此一來混亂可想而知。這就是乙個典型
的有符號/無符號不匹配錯誤。再看一段**:
unsigned long a = 0;
long b = 0;
long c = 1;
if( (a - c) < b )
if( (a - 1) < b )
這段**的兩個if語句的if分支有可能執行嗎?答案是絕無可能。因為表示式(a - c)的型別不是long,而是unsigned long,它的值絕不會小於b(即0)。同樣地,表示式(a - 1)的值也永遠大於等於0。
上面兩個例子代表了我們在寫程式時經常會犯的錯誤:無意識地濫用型別不匹配的變數、表示式(尤其是有符號型與無符號型)之間的賦值與比較。
有什麼辦法能預防這種錯誤嗎?事實上如果你足夠警覺,將編譯器的編譯警告開關設為最高端(比如vc7.1的4級: /w4),那麼任何乙個負責
任的編譯器都會在上述情況下明白無誤地警告你。順便說一下,vc工程中預設的編譯警告為3級,此時編譯器的責任心就大大降低了,對上述
的危險情況根本視若無睹。
所以為了讓自己能夠睡個安穩覺,首先應當盡量避免使用相異型別之間的賦值、比較。然後設定開發工具的檢查為最嚴格等級,讓它們能
幫我們盡早地嗅出這類潛在的危險。
shell 比較邏輯表示式
a file 如果 file 存在則為真。b file 如果 file 存在且是乙個塊特殊檔案則為真。c file 如果 file 存在且是乙個字特殊檔案則為真。d file 如果 file 存在且是乙個目錄則為真。e file 如果 file 存在則為真。f file 如果 file 存在且是乙個...
C語言的表示式求值問題(整型提公升)
表示式求值的順序一部分是由操作符的優先順序和結合性決定。同樣,有些表示式的運算元在求值的過程中可能需要轉換為其他型別。隱式型別轉換 c的整型算術運算總是至少以預設整型型別的精度來進行的。為了獲得這個精度,表示式中的字元和短整型運算元在使用之前被轉換為普通整型,這種轉換稱為整型提公升。為什麼要整型提公...
表示式隱式型別和整型提公升
算術轉換 c的整型算術運算總是至少以預設整型型別的精度來進行的。為了獲得這個精度,表示式中的字元和短整型運算元在使用之前被轉換為普通整型,這種轉換稱為整型提公升。表示式的整型運算要在cpu的相應運算器件內執行,cpu內整型運算器 alu 的運算元的位元組長度 一般就是int的位元組長度,同時也是cp...