星期一, 6月 13, 2011

Code Better -- 寫C常犯的錯

這是公司內部的訓練課程,提醒了一些C coding常犯的錯誤,所以做個筆記記錄下來(為何不提供電子檔下載呢?)。


變數的初始化和邏輯流程控制
藍色的部分,是寫code新手常會遺漏的。


Leak of File Handle and Memory
在Linux裡面,file handle的數目是有限制(pipe、socket亦然),所以有open必然要去考慮是否有close。程式中間出現return,就要特別小心。此外,就是要避免Magic Number。


底下改寫的例子,其實在file open failed的情況,不要直接return error code比較好。因為他日若有別人在開檔之前做其他resource allocation的判斷,可能也會造成leak。講者是為了投影片幾不了那麼多字,而簡單用return -1帶過。


字串的使用
一樣先來一段有問題的code。

在function裡面宣告的變數,是儲存在stack的空間中,當function return之後,也就被pop掉,所以return的指標不知指往何處(func4_1)。而在function中使用static則是會有function無法reentrant使用的問題;這跟把output存在global變數是一樣的意思(func4_2)。


比較好的寫法有以下兩種。

首先是POSIX常見的寫法,在function外面先準備好字串,再傳進function裡面做事。


再來則是C Lib常見的作法。在function中malloc好字串空間,使用完function之後,再將之free。因為malloc的空間是存在heap中,所以不會因為function return而消失(如stack)。


Signed and Unsigned Char
有時候我們都會習慣拿char來做數字運算,不過最好在char之前加上signed或是unsigned,因為char只有8 bits,一下子就到bundary(2的8次方:256、7次方:128)。在boundary上頭,若沒有給signed或unsigned對於數值的判斷就變成因compiler而定。

signed char:
0 => zero
127 => positive
128 => negative
-1 => negative
unsigned char:
0 => zero
127 => positive
128 => positive
-1 => positive


i++、++i的迷思
從以前我就一直對於複雜的i++或++i使用很不熟,始終認為是自己寫code功力不夠的關係,到今天才知道,原來在複雜的使用情況下,i值的運算順序也是可能因compiler而異,甚至compile code時有無最佳化、最佳化的程度都有影響(根據主講人說,在VC5.0上不同最佳化的程度產生的結果居然不同!還GCC不是)!



基於好奇心,我也try了這個sample code(多加了一些printf),GCC和cygwin就有一些些不一樣。至於裝VC去試就算了,VC又肥,要移除還會留下『足跡』。除此之外,運算出來的結果也在我意料之外,儘管根據結果可以去推出為什麼。所以,用一些變數將過程中暫時的運算結果記下來會比較保險。

GCC
i: 3, ++i: 3, ++i: 3(cygwin在這裡是:i: 3, ++i: 3, ++i: 2
j: 1, i: 4
func6_1: x (before) = 4, x (after) = 40
func6_1: x (before) = 6, x (after) = 60
k: 2400
func6_1: x (before) = 7, x (after) = 70
func6_1: x (before) = 7, x (after) = 70
m: 4900, i: 8

沒有留言: