有個國外團隊檢測了 200 多個 C/C++ 開源專案,包括了 Php、Qt 和 Linux 核心等知名專案。於是他們每天分享一個錯誤案例,並給出相應建議。本篇案例來自 Wolf 原始碼。
錯誤的程式碼:
1 2 3 |
ID_INLINE mat3_t::mat3_t( float src[ 3 ][ 3 ] ) { memcpy( mat, src, sizeof( src ) ); } |
說明:
有時候程式設計師會忘記 C/C++ 裡陣列不能按值傳遞給函式。當你試圖這樣做時,是陣列的指標(第一個元素的地址)而不是整個陣列被傳遞。我們還應該記住,方括號中的數字沒有任何意義。它們僅僅是程式設計師所做的標誌,記錄了傳遞陣列的『假定』大小。事實上,你也可以傳遞一個大小完全不同的陣列。例如,下面的程式碼就會成功編譯:
1 2 3 4 5 6 |
void F(int p[10]) { } void G() { int p[3]; F(p); } |
相應的,sizeof(src) 運算子表示的不是陣列的大小,而是指標的大小。結果就是 memcpy() 僅複製了陣列的一部分。也就是4或8位元組,這取決於指標的大小(外部結構體不算)。
正確的程式碼:
這樣的程式碼最簡單的變形像這樣:
1 2 3 |
ID_INLINE mat3_t::mat3_t( float src[ 3 ][ 3 ] ) { memcpy(mat, src, sizeof(float) * 3 * 3); } |
建議:
有幾種讓你的程式碼更安全的方法。
陣列大小已知。你可以在函式中使用陣列的引用。但並不是每個人都知道可以這麼做,知道如何編寫這樣的程式碼的人則更少。所以我希望這個例子是有趣並有用的:
1 2 3 4 |
ID_INLINE mat3_t::mat3_t( float (&src)[3][3] ) { memcpy( mat, src, sizeof( src ) ); } |
現在就可以給函式傳遞大小正確的陣列了,而且最重要的是,sizeof() 得到了陣列的實際大小。
解決這個問題的另一個方法是使用 std::array 類。
陣列大小未知。一些書的作者建議使用 std::vector 類,或者其他相似的類。然而實際中這樣做並不總是很方便。
有時你想用一個簡單的指標。在這種情況下,你應該向函式傳遞兩個引數:一個指標和元素的數量。然而,總的來說這不是一個好做法,它會導致很多 bug。
這種情況下,可以去讀一下《C++核心指南》中的一些想法。我建議看《不要用一個單獨的指標傳遞陣列》章節。總而言之在你有空時讀讀《C++核心指南》總是有好處的。裡面有很多有用的想法。