編譯程式失敗的話,編譯器一定會告訴你是什麼地方出錯了,千萬不要嘗試自己盯著程式碼尋找錯誤,而不理會錯誤訊息。
很多常見的語法錯誤,看一眼編譯時的錯誤訊息就會知道在哪裡了,像是:
#include <bits/stdc++.h>
using namespace std;
int main() {
int a = 5
}
雖然讀者應該一眼就可以發現第 4 行少了一個分號,不過要是程式大一點的話,要靠自己找到就不是簡單的事了。編譯時,編譯器就會說:
semicolon.cpp: In function 'int main()':
的意思就是這個錯誤發生在 semicolon.cpp
這個檔案的 int main()
函式裡頭,下一行的 semicolon.cpp:5:1
是說這個錯誤發生在 semicolon.cpp
的第 5 行的第 1 個字元,後面的 expected ',' or ';' before '}' token
則是說發生了什麼,意思是那一個 }
前面缺少了 ,
或 ;
。總之只要去看看第 5 行附近,就可以馬上看出來是上一行缺少一個 ;
了。
有時候錯誤訊息會讓人有點摸不著頭緒,畢竟編譯器其實不會通靈你想做什麼,像在剛剛的例子裡面,編譯器指出錯誤的那一行只有一個 }
,要往前看才知道是前一行少一個分號。比較顯著的例子是,要是發生的錯誤是多層大括號之中少打一個,那編譯器當然分不出來你是少打哪一個,舉例來說:
#include <bits/stdc++.h>
using namespace std;
int main() {
int n = 5;
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
if (i != j) {
cout << i << " " << j << "\n";
}
}
cout << "ok!\n";
}
編譯器抱怨的是檔案最後面應該還要有一個 }
,不然 int main(){
的 {
會沒有對應的 }
。不過從程式碼的縮排看起來,應該是 for(int j = ...){
少了對應的 }
,要是直接照著指示補在最後面那就錯了。因此,編譯失敗時還是得自己看看前後文來發現真正的錯誤是什麼。
剛才的例子裡面,錯誤訊息裡出現了 error 和 note,有時候還會有 warning。note 是用來補充說明 error 或 warning 用的,而 error 是一定得要修好,不然不能編譯的錯誤,warning 則是編譯器提醒你這樣的寫法可能會容易出錯,但不修好也可以編譯成功。
一個會製造出 warning 的例子是 printf("%d");
,編譯器會警告 printf
應該要有一個 int 參數,但沒有的話編譯也是可以過的。
除了指出問題的位置可能會怪怪的,錯誤訊息的描述有時候也會比較難懂,像是
#include <bits/stdc++.h>
using namespace std;
int count = 0;
int main() {
cout << count << "\n";
}
天哪,ambiguous 的是他自己吧!什麼叫作 reference to 'count' is ambiguous
呢?看到下面的 note 列出了三個不同的 count
,有兩個在詭異的檔案裡面,最後一個是我們的全域變數,原來是 count
跟已經存在的東西撞名了,在有 using namespace std;
的時候要特別注意全域變數取名字不要跟 STL 裡的 function 撞名。
神奇的是,區域變數取相同的名字是不會有問題的,編譯器會優先使用區域裡定義的東西。例如上面那份程式碼裡面,只要把 count
移到 main
裡就可以正常編譯,不過,這樣在 main
中就只能用我們定義 count
變數,而不能直接使用 STL 裡的 count
函式,得要寫 std::count
指定要使用 STL 中的 count
才可以。
前面的錯誤訊息都還算是可以閱讀。有時候錯誤訊息會有超長一大串,例如:
#include <bits/stdc++.h>
using namespace std;
int main() {
vector<vector<int>> a(5, 10);
}
(下面還有一長串,讀者可以自己試試看。)
看這種訊息的方法就是直接忽略下面全部的東西,找出編譯器指出我們的錯誤的地方,也就是直接看到最上面的 vector.cpp:4:32
,需要看的部分就只有這裡而已,總之就是 vector
初始化的寫法錯了。在使用 STL 裡提供的容器時很容易出現這樣的錯誤訊息。
以上介紹了錯誤訊息大致的讀法,可能會出現的錯誤訊息還有很多種,別忘了編譯失敗時要先從錯誤訊息下手,而看到一大串錯誤訊息也不要驚慌,只要找出寫著錯誤位置的部分就可以了。至於看不懂錯誤訊息的話,通常直接複製錯誤訊息的敘述,拿去搜尋就可以找到解法了。