Catch Bug

1. Makefie與環境變量

編譯某一源碼時,我直接把LIBRARY_PATH,和LD_LIBRARY_PATH寫在Makefile裏,並自作聰明地加上了export。
這導致系統根本找不到庫的路徑。

//原因
系統環境變量可以在make開始運行時被載入到Makefile文件中。
但如果Makefile中已定義了這個變量,或是這個變量由make命令行帶入,那麼系統的環境變量的值將被覆蓋。
(如果make指定了“-e”參數,那麼,系統環境變量將覆蓋Makefile中定義的變量) 

比如:在環境變量中設置了“CFLAGS”環境變量,那麼可以在所有的Makefile中使用這個變量了。
這對於我們使用統一的編譯參數有比較大的好處。
如果Makefile中定義了CFLAGS,那麼則會使用Makefile中的這個變量,如果沒有定義則使用系統環境變量的值。
這類似“全局變量”和“局部變量”的特性。 
(故上面的LIBRARY_PATH,和LD_LIBRARY_PATH變成了Makefile的變量)
當make嵌套調用時,上層Makefile中定義的變量會以系統環境變量的方式傳遞到下層的Makefile中。
默認情況下,只有通過命令行設置的變量會被傳遞。
定義在Makefile文件中的變量,如果要向下層Makefile傳遞,則需要使用exprot關鍵字來聲明。 

實際上,最好不要把許多的變量都定義在系統環境中,因爲在執行不同的Makefile時,擁有的是同一套系統變量,這可能會帶來更多的麻煩。 

2. 除法

DWORD dwSpeed = 2;
dwSpeed = dwSpeed / 2; //區別 dwSpeed / 2.0
if ( 0 == dwSpeed )
    dwSpeed = 1;
//這樣求時間的時候,纔沒有錯誤
dwTime = dwDistance / dwSpeed;

3. 指針

由函數獲得指針,一定要判斷是否爲空才能使用,無論這個指針是否智能指針

std::shared_ptr<T> pShared = getSharedPtr();
if (pShared)
{
    //處理
}

4. GDB等待崩潰

服務器的程序運行後,可以直接打開“gdb -p 進程”, 等待服務器的崩潰。

5. 程序是否死循環

可以用 “top” 命令觀察 當前進程消耗的計算資源

6. 浮點數間判斷大小 與 判斷一個浮點數是否爲0.000000

(1)計算機表示浮點數(float或double類型)都有一個精度限制,
對於超出了精度限制的浮點數,計算機會把它們的精度之外的小數部分截斷。
因此,本來不相等的兩個浮點數在計算機中可能就變成相等的了。
例如:
A. float a=10.222222225,b=10.222222229
數學上a和b是不相等的,但在32位計算機中它們是相等的。
B. fabs(a) < eps, 則可以認爲a 爲0
如果兩個同符號浮點數之差的絕對值小於或等於某一個可接受的誤差(即精度),就認爲它們是相等的。

(2) 不要直接用“==”或者“!=”對兩個浮點數進行比較,
但是可以直接用“<”和“>”比較誰大誰小, 或使用庫函數 std::isgreater(a, b) isgreaterequal等。

7. 浮點數累加

場景:一個1等兵(符號ARMY1)戰鬥力爲1.11, 一個二等兵(符號ARMY2)戰鬥力爲1.22,一個三等兵(符號ARMY3)戰鬥力爲1.33。如何處理它們間的累加情況?

如果設總戰鬥力爲 double sum。那麼
sum = 1.11 * ARMY1 + 1.22 * ARMY2 + 1.33 * ARMY3。
如果又新增一個1等兵。那麼
sum = sum + 1.11 * 1。
多次累增後,會累增浮點數間的誤差。
解決方法如下:
每種兵的戰鬥裏都乘100, 那麼
int sum = 111 * ARMY1 + 122 * ARMY2 + 133 * ARMY3。
整數相加不會累加誤差。當客戶端需要顯示戰鬥力時,
double show_sum = sum / 100.0。

8. probuf的解析字節大小

場景:對某一個區域,刷新城堡的時候。曾經把區域內的所有城堡信息通過repeated填充了一個probuf。當probuf的字節數量到達1.5萬以上的時候,會導致客戶端解析出錯。
解決:每填充一定數量的repeated,就發送。

MSG_Ret_CS sendMsg
for ( int i = 0; i <n;++i)
{
  Point * p = send.add_pont();
  fill(p);
  if ( 0 == i % 10 )
  {
>    sendMsg(p);
>  send.Clear();
  }
}
//注意最後要發送剩餘的
send(p);

9. string.c_str()

void doSomething(const char* str);

std::string str; 
doSomething(str.c_str());
  • str.c_str()的生存期是由str管理的,如果str銷燬,c_str()也會銷燬了。-
  • 如果doSomething()繼續處理這個指針, 會導致coredump。

10. std::vector的一個誤區

class A
{

};
std::vector<A>  vecArray;

vecArray.push_back(  );
vecArray.push_back(  );
vecArray.push_back(  );

A & a= vecArray.back();  //有潛在錯誤
vecArray.push_back(  );
  • vector是一個會自增長的容器,自增長的結果就是
    把原來的內存釋放掉,重新分配一個足夠大的內存。
    既然原來的內存已經釋放掉,
    那麼a所引用的內存就是一段無效的內存。

  • 解決方法也很多,最簡單就是用std::list或者std::deque替代vecto

發佈了30 篇原創文章 · 獲贊 36 · 訪問量 23萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章