最近將手頭上負責的專案代碼從GCC 4.8.2升級到了GCC 8.2,(終于可以使用C++17了,想想后續的開發也是很美好啊~~)不過這個程序之中也遇到了一些稀奇古怪的問題,在這里做一個簡單的記錄,希望后續有同學遇到類似的問題能作為參考,
1. error: unable to find string literal operator 'operator"
這個我感覺是歷史的遺留問題了,從C++11開始就不支持字串字面量后面直接連接變數名,GCC 4.8.2應該是沒有支持該編譯檢查,所以后續升級8.2的時候報了類似的錯誤,
聽著有些抽象啊,舉個栗子:
#define LOG(fmt, ...) printf("[%s][%s][%d]:"fmt "\n", __FILE__, __FUNCTION__,\
__LINE__, ##__VA_ARGS__)
上面是一段C++常用的日志宏定義,在宏定義展開的時候,編譯器會默認將[%s][%s][%d]:,fmt,"\n"字面量拼接在一起,然后和后面行號等宏定義作為參賽列印出來,
#define LOG(fmt, ...) printf("[%s][%s][%d]:" fmt "\n", __FILE__, __FUNCTION__,\
__LINE__, ##__VA_ARGS__)
2. error: flexible array member not at end of struct
在C++之中,給定了一個結構定義和一個指向結構的指標,編譯器必須能夠通過指標偏移的方式訪問該結構的任何成員,由于結構中每個成員的位置都取決于其前導成員的數量和型別,因此訪問任何結構都需要知道所有前導成員的數量和型別,
在結構體之中,如果是陣列為結構體之中最后的成員,這并不違反上述的編譯規則,但是,如果flexible array member出現在了結構體末尾以外的任何位置,則其后的任意成員的位置都將取決于陣列中對應的型別的個數,所以編譯器禁止將沒有定義長度的陣列作為結構體的中間成員,
舉個栗子:
struct S {
int a;
char b[];
int c;
};
這里由于b成員的長度是不確定的,所以編譯器無法通過S的指標推斷出成員c的位置,所以編譯報錯:

而我們看如下的結構體就沒有編譯報錯的問題了:
struct S {
int a;
int c;
char d[];
};
看到這,可能有些讀者會問了,如果我就是需要在結構體之中定義兩個變長的陣列,能怎么辦呢? 筆者有覺得有下面兩種方式實作:
- 用指標啊!!!把結構定義為下面這種形式就可以了
struct S {
int a;
char b[0];
int c;
char d[];
};
- 如果b和d成員長度一致或者不在記憶體損耗的情況,也可以采用如下方式來定義這個結構體:
struct Pair {
char b;
char d;
}
struct S {
int a;
int c;
Pair p[];
};
3. 回傳值的坑
有回傳值的函式沒有指定return,或是return了卻沒有給出回傳值在gcc進行-O優化等級大于1時,會出現各種稀奇古怪的core,筆者也是通過GDB除錯了很久,最終通過編譯器的警告發現了上述的問題,
這個理論上是一個很低級的錯誤,但是筆者花了比較長的時間排查,因為出現的實在是有些詭異,
我們來看如下代碼:
int test(int a, int b) {
auto c = a + b;
}
int main() {
auto c = test(10, 20);
return 0;
}
上面我們可以看到test函式本身是需要回傳一個int類似作為回傳值的,但是這里并沒有進行應有的回傳,
上述代碼在GCC 4.8.2之中并不會出現問題,但是一旦切換到GCC8.2之后,并且在編譯優化等級大于1的時候,就會core在這個函式的執行代碼位置,
所以為了規避上述的問題,筆者這里推薦使用GCC編譯時開啟編譯選項:-Werror=return-type,這樣,有上述回傳值問題的代碼就會在編譯期間被編譯器識別并報錯,(其實引數-W,-Wall編譯器是會對上述問題報警的,但是warning嘛,大家經常就不care啊~~~)
4.小結
簡單總結了一下筆者升級GCC程序之中遇到的一些小的編譯問題,希望可以幫助到同樣問題的同學,GCC8.2也囊括了絕大多數C++17的新特性和部分的C++2a的特性,各種新的語法糖在編碼程序之中也能極大的提高開發效率,Enjoy your modern CPP,
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/63261.html
標籤:C++
上一篇:位運算介紹 & 應用
