※ 引述《david830317 (dd810)》之銘言:
: 開發平台(Platform): (Ex: VC++, GCC, Linux, ...)
: Xcode
: 額外使用到的函數庫(Library Used): (Ex: OpenGL, ...)
: 問題(Question):
: 在xcode時用void以外不能用reture
: 錯誤結果(Wrong Output):
: Control may reach end of non-void function
: 程式碼(Code):(請善用置底文網頁, 記得排版)
: http://ideone.com/T36LJH
: 補充說明(Supplement):
關於這個 function 的寫法
float Quantity::calcValue() const
{
if (unit >= 1 && unit <= 10)
{
return unit * 3.00;
}
if (unit >= 11 && unit <= 50)
{
return unit * 2.50;
}
if (unit >= 51)
{
return unit * 2.00;
}
}
我比較建議用 if-elseif-elseif 的結構來寫:
float Quantity::calcValue() const
{
if (unit >= 1.0f && unit <= 10.0f) {
return unit * 3.00f;
} else if (unit > 1.0f && unit <= 50.0f) {
return unit * 2.50f;
} else if (unit >= 50.0f) {
return unit * 2.00f;
} else {
/* default */
return unit;
}
/* Unreached */
}
原因:
1. 這樣才看得清楚這三條 if 其實是負責同一件事,條件排列整齊後,漏網之魚也
在 default 那一區塊有處理,不管是 error handling 還是 return default,
而且所有的狀況在 if-else 結構內都會 return,能輕易判斷函式終結點。
2. float 運算時,不管是比大小還是運算,最好兩邊都是 float (10.0f),
你有些寫 int,問題倒還不大反正會轉成 float,但有些寫 double (2.50) 就
會兩邊都轉成 double 運算,運算完再轉 float 再 return,浪費效能。
另一個問題點,你大概一開始把 unit 定義為 int 後來才改 float,
所以 if 裡面完全沒有處理到 10.0f<unit<11.0f, 50.0f<unit<51.0f 的狀況,
如果習慣把常數的 data type 也寫對,遇到可能有問題的狀況,心中自然會產生
違和感,覺得這樣寫怪怪的。你寫 10.0f 時就會考慮 10.5f 會發生什麼事
3. 最後註解 Unreached 其實很有必要,照我的寫法所有狀況都應該在 if-else 的
結構內 return,所以不會跑到 Unreached 那邊。但就是有些人在修改 code 時
會呆呆加在後面,以為 if 跑完就會跑他加的東西,所以要註解提醒。
實務上有很多地方需要這樣的防呆措施,不只是合作寫程式防別人耍呆,很多
時候自己也會發蠢,
* * *
舉另一個經典例子:
if (unit > 1.0f)
return unit*3.0f;
這樣寫在 C/C++ 是允許的,省略大括號。但是就有人這樣插一行...
if (unit > 1.0f)
printf("Using 3.0 ratio.\n");
return unit*3.0f;
結果變成不管 unit 值多少,有沒有 print 那行字,都變成 return unit*3.0f 了
所以我會嚴格要求如果 if 的內容分成兩行寫,一定要加大括號
if (unit > 1.0f) {
return unit*3.0f;
}
或這樣也行
if (unit > 1.0f)
{
return unit*3.0f;
}
寫成同一行的話隨便你加不加
if (unit > 1.0f) return unit*3.0f;
大家應該會覺得是插入新行卻不長眼看清楚的那個人的錯,我也覺得是他的錯,
但是這種狀況實在太多太多了,大家都是用 Ctrl-C & Ctrl-V 在寫程式的樣子,
熬夜拼命貼的時候就常常貼錯地方,只好設法定一些規則防呆。
這樣至少你 code review 時就可以檢查大括號來預防出錯,而不是每次 release 的
前一天晚上才在抓幾百個這種無腦錯誤。