1. 編譯環境使用VS2008,在調試過程中發現,某個函數的部分代碼沒有正確執行,在這部分代碼處打斷點調試,發現每次調試運行時總是提示斷點無效。出問題的代碼如下,在while(){}代碼塊內部打斷點提示斷點無效。
[cpp]
INT32 sendLTEMsg(void *pMsg, INT32 iMsgLen)
{
INT32 t_iLeft = iMsgLen;
INT32 t_iRet = 0;
INT32 t_idx = 0;
if((NULL==pMsg) || (0==iMsgLen))
{
return FALSE;
}
while(t_iLeft>0) /*保證將數據全部發送出去*/
{
t_iRet = send(g_SockClientLTE, &(((char*)pMsg)[t_idx]), t_iLeft, 0);
if(t_iRet == 0)
{
break;
}
else if(t_iRet == SOCKET_ERROR)
{
INT32 t_errcode = WSAGetLastError();
return FALSE;
}
t_iLeft -= t_iRet;
t_idx += t_iRet;
}/*end of while*/
return TRUE;
}
2. 那麼,在什麼情況下會導致運行時斷點無效或不能在指定的位置打斷點呢?
a) 是否編譯時存在調試信息?
需要查看編譯選項,debug or release(說白了就是編譯時的optimizationlevel),debug會存在調試信息。
b) 在編譯完成之後代碼是否有改動?
代碼可能已經和可執行文件不一致,導致打斷點的位置和預期程序執行的位置不一致。如下圖,斷電停在a--的位置,但是程序已經輸出了hello world。
c) 是否將這部分代碼編譯到了目標文件?
比如條件編譯的影響,沒有對這部分代碼進行編譯,當然就不可能打斷點。那麼,如何判斷代碼是否編譯到了目標文件?
3. 預處理指令#pragma
#pragma指令的作用是設定編譯器的狀態或者是指示編譯器完成一些特定的動作。#pragma指令對每個編譯器給出了一個方法,在保持與C和C++語言完全兼容的情況下,給出主機或操作系統專有的特征。依據定義,編譯指示是機器或操作系統專有的,且對於每個編譯器都是不同的。語法:#pragma para
#pragmamessage(“string”) 編譯時顯示一條信息
#pragmacode_seg(["section-name"[,"section-class"] ] ) 設置程序中函數代碼存放的代碼段
#pragmawarning(…) 對warning進行處理
#pragmacomment(…) 將一個注釋記錄放入一個對象文件或可執行文件中
如下實例中,如果代碼中不加pragma預處理指令,編譯時會提示4013的warning,pragma可以禁止提示某個warning信息,並且可以設置顯示編譯時的消息
4. 在問題代碼while(t_iLeft>0)前後使用預編譯命令#pragma message(…),發現while()語句前都進行了編譯,語句後沒有編譯到目標文件。這是為什麼?
個人認為是C編譯器詞法分析“貪心法”(見後面說明)導致的,我們注意到while()語句後面存在中文注釋,在中文後加一個空格,編譯信息出現。編譯器在對代碼進行編譯過程中,中文字符“去”對之後的*結合,導致編譯器認為while()後的注釋沒有結束,函數中兩個注釋之間的代碼都被視為注釋!(這可能是由於編譯器對字符編碼的認識不一致導致的,原因為猜想,在VC6環境下編譯沒有出現此問題)
簡要說明什麼是貪心法:
我們從剛學C語言就有一個疑問:怎樣解釋a+++b?
如果編譯器的輸入流截止至某個字符之前都已經被分解為一個個符號,那麼下一個符號將包括從該字符之後可能組成一個符號的最長字符串。符號之間不能有空格。
比如:
[cpp] int a = 3, b;
int *p = &a;
b = 12/*p /* comment */ ;
int a = 3, b;
int *p = &a;
b = 12/*p /* comment */ ;
b的值是幾?
或者
[cpp] int *p = NULL;
int i = sizeof*p;
int *p = NULL;
int i = sizeof*p;
這種表示會是錯誤的嗎?
大家有興趣可以試試。
摘自 nevasun的專欄