1. 程式人生 > >keil MDK編譯器警告和錯誤詳解(不定期更新)

keil MDK編譯器警告和錯誤詳解(不定期更新)

工作後從微控制器轉成ARM,剛開始用ADS1.2編譯器,用了一段時間,因為我接手的專案的老程式正是用ADS編譯的,部門也大都在用.在學微控制器的時候用的是keil c51編譯器,ads和這個編譯器在易用性上真是無法比較.後來漸漸知道keil已經被arm公司收購,現在keil MDK成為了arm官方編譯器,所以決定重新投奔keil,利用平時的時間,將原程式重新用mdk編譯.mdk的優點就沒必要說了,在這裡把平時遇到的編譯器給出的警告和錯誤資訊給出詳解,希望給初學者一點幫助,發現錯誤,需要補充的歡迎留言.

1.warning:  #550-D: variable "d" was set but never used
描述:變數'd'定義但從未使用,或者是,雖然這個變數你使用了,但編譯器認為變數d所在的語句沒有意義,編譯器把它優化了.
解決:仔細衡量所定義的變數d是否有用,若是認定變數d所在語句有意義,那麼嘗試用volatile關鍵字修飾變數d,若是真的沒有用,那麼刪除掉以釋放可能的記憶體.

2.warning:  #1-D: last line of file ends without a newline
描述:檔案最後一行不是新的一行.編譯器要求程式檔案的最後一行必須是空行,想了半天沒想通為什麼要這樣.
解決:可以不理會.若是覺得出現警告不爽,那麼在出現警告的檔案的最後一行敲個回車,空出一行.

3. warning:  #111-D: statement is unreachable
描述:宣告不可能到達.多出現在這種場合:

 int main(void)
 {
       ...
       while(1)  //無限迴圈,這在不使用作業系統的程式中最常見
       {
             ...
       }
       return 0; //這句宣告在正常情況下不可能執行到,編譯器發出警告
 }
解決:不理會.

4. warning: C3017W: data may be used before being set
描述:變數'data'在使用前沒有明確的賦值.如:

 uint8 i,data;            //定義變數i和data,二者都沒有明確賦值
 for ( i = 0; i < 8; i++) //變數'i'在語句中被賦值0
 {
     if ( IO1PIN & SO_CC2420 )
         data |= 0x01;    //變數'data'在使用前沒有明確賦值,編譯器發出警告
     else
         data &= ~0x01;
 }

解決:應仔細衡量該變數的初始值是否為0,若是,可以不理會這個警告,因為MDK編譯器在程式執行前,會將使用到的資料區初始化為0,但若是該變數的初始值不應該是0,忽略這個警告可能會引起致命錯誤.這個警告應引起足夠重視.應養成變數賦初值的習慣,好在有編譯器給把關.

5. warning:  #177-D: variable "temp" was declared but never referenced
描述:變數'temp'進行了宣告但沒有引用.多出現在聲明瞭一個變數,但卻沒有使用它,它和warning:  #550-D: variable "temp" was set but never used不同之處在於temp從沒有使用過.
解決:若是定義的變數確實沒有用,刪除掉;若是有用,則在程式中使用.
與該警告類似的還有 warning:  #177-D: function "MACProcessBeacon" was declared but never referenced

6. warning:  #940-D: missing return statement at end of non-void function "DealwithInspect2"
描述:返回非空的函式"DealwithInspect2"的最後缺少返回值宣告.如:

 int DealwithInspect2(uint32 test)
 {
      ...
      ...
      ...
     //此處應該是return x;返回一個int型資料,若是沒有返回值,編譯器產生警告
 }

7..warning:  #1295-D: Deprecated declaration lcd_init - give arg types

描述:在定義函式的時候,如果你寫上函式引數,就會有這個警告,比如void timer_init(); 這裡就沒有形參,如果這樣的話,編譯器會給出警告.

1. error:  #65: expected a ";"
描述:缺少分號.大多是漏忘';'.
解決:雙擊錯誤行,在定位到錯誤點的附近找到沒加';'號的語句,加上分號.並不一定在定位到的錯誤行才卻分號,可能是這行的上一行,也可能是下一行.

2. error:  #65: expected a ";"和 error:  #20: identifier "xxxx" is undefined一塊出現,而且後面的error: #20錯誤可能一大堆
描述:這個錯誤對於第一次遇上的人來說絕對是個噩夢,當錯誤出現,滿懷希望的雙擊錯誤提示,來到錯誤行時卻愕然發現,錯誤行絕對沒有錯,於是找找錯誤行的上一行,下一行,沒有錯誤,再找上上行,下下行...讓人無比鬱悶的事情出現了:編譯提示的所有錯誤行都不可能有錯誤出現.其實這最可能是你在.h檔案宣告外部變數或者函式時,沒有在宣告語句的最後加分號!如果你有很多模組,如main.c,lcd.c,key.c...有很多標頭檔案,如lcd.h,key.h,若是在lcd.h檔案宣告函式時沒有加分號,那麼這種錯誤可能定為到main.c中,所以要檢查所有標頭檔案.
解決:仔細檢查.h檔案,將分號補上.

3.  Error: L6200E: Symbol flagu multiply defined (by uart0.o and main.o).

描述:變數(也是一種符號)flagu多處定義(在uart0.c中和main.c都定義了).通常錯在全域性變數定義重複.比如:在main.c中定義全域性變數flagu:

      uint8 flagu=0;

在uart0.c中也用到該變數,於是宣告此變數,我通常都是先複製定義的變數再在變數前面加關鍵字extern修飾:

      extern uint8 flagu=0;

然後編譯,就會出現上面的連線錯誤,原因在於,我在uart0.c中是又定義了一個變數,而不是宣告變數,因為我給變數賦了初值"flagu=0",這樣就重複定義了變數flag.正確的宣告方法是去掉賦值部分:

      extern uint8 flagu;

解決辦法:找到重複定義的變數,看情況修改一處.

4.error:  #159: declaration is incompatible with previous "wr_lcd" (declared at line 40)
描述:在wr_lcd函式還沒有宣告之前就已經使用了.多出現在兩種情況:第一種,wr_lcd函式體還沒有寫,就已經用到了它,這種情況多出現在寫一個程式的大體結構中,只是簡單寫一下框架.第二種情況比較常見,函式a呼叫函式b,但函式b的函式體在函式a的下面:

void a(void) //函式a的實體
{
     b(); //呼叫函式b
}
void b(void) //函式b的實體
{
     ...
}

這樣如果點編譯,就會產生error:  #159的錯誤,因為當函式a呼叫函式b時,發現在這之前都沒有函式b的任何宣告.
解決方法:在函式a呼叫函式b之前,對函式b進行宣告,如:

void b(void); //對函式b進行宣告
void a(void) //函式a的實體
{
     b(); //呼叫函式b
}
void b(void) //函式b的實體
{
     ...
}
 5. error:  #137: expression must be a modifiable lvalue

描述:表示式必須是一個可以修改的左值.主要出現在這種現象:

                 a=NUM;

NUM是一個數值或表示式,a為一個變數,但a被定義為像const這種不可更改的型別,導致NUM不能賦值給變數a.

解決方法:要麼放棄賦值,要麼修改變數屬性.

6.error:  #18: expected a ")"
如果是出現在c檔案中, 多半是因為少了一個")",或者錯誤行有編譯器不識別的字元

如果出現在標頭檔案中,錯誤行又是一個函式宣告,多半是因為在函式宣告中有編譯器不認識的字元.

7.error:  #7: unrecognized token

未識別的標記,多半是切換成了中文標點。