1. 程式人生 > >typedef重複定義 和 error: ‘long long long’ is too long for GCC

typedef重複定義 和 error: ‘long long long’ is too long for GCC

今天發現一個很有意思的編譯問題,然後在Stack Overflow上也有看到類似的。就是出現了 long long long 型別錯誤提示

錯誤提示如下:

/home/yejy/algorithm_and_data_structure/main.cpp:50:17: error: ‘long long long’ is too long for GCC

#define INT64   long long

                 ^

顧名思義,一個long佔4個位元組,兩個就是8位元組,總共64位,等於系統是64位的,如果你使用3個long那就96位了,那肯定會有問題,正常情況下也沒人會定義三個long。

#define INT64   long long

然後看程式碼出錯的地方,就是一個巨集定義,怎麼會出現問題呢? 然後仔細看了一下程式碼發現是連結外部庫導致的,工程 A 連結了 B_lib.so 和 C_lib.so 兩個動態庫, 然後 B 中用巨集定義了 long long , C 中使用typedef重新命名了 long long,順序剛好是巨集定義在前,等價於下面兩句程式碼:

 #define INT64   long long

typedef long long INT64;

因為巨集定義只是簡單的替換,因此導致typedef變成了:

typedef long long long long long;

這應該屬於比較典型的連結多個外部庫導致的程式碼衝突問題,然後自己大概思考了一下,併到google上檢索了相關問題的解決,在這裡總結一下,問題的解決思路主要應該有以下幾種:

1. 同一個專案使用同一份基礎型別定義標頭檔案

在同一個專案當中,當然最好肯定是所有庫都引用同一個標頭檔案中的基礎型別typedef定義是最好的,這樣就不會出現不必要的衝突,在專案一開始的時候就規定好相關的基礎型別定義的地方。然後因為這邊是外部庫,因此想把所有基礎型別都定義到同一個檔案不太現實,因此這種方式對於上述問題並不適用,但是如果不是外部庫的話,這個還是要注意的。整個工程都用一份,對於不同平臺可以做一下區分。

2. 將問題有編譯階段推遲到連結階段

由於大部分錯誤都是redefinition; different basic types,當然我這個比較奇葩,這些錯誤都是發生在編譯階段,那我們只要保證在編譯的過程中不衝突就可以了,也就是讓兩個衝突的typedef不在同一個程式碼檔案中使用。像我這個問題,include的標頭檔案的時候,先include包含typedef的檔案,然後再include包含巨集定義的檔案,那編譯也是可以通過的。然後對於兩者完全衝突,保證不在一個程式碼檔案中使用就不會有問題(可考慮通過extern來隔離相關介面的定義,就是將呼叫發生衝突型別的流程放到其他檔案中處理)。到了連結階段,因為這個時候都是以原始型別為基準,因此也不會有問題。如果是臨時引用兩個庫出現問題,應該就只能通過這個方式來嘗試了。

extern方式可參考該連結:extern 隔離

3. 在C++語言中使用名稱空間(namespace)

這個應該是可以解決問題的,但是需要庫的開發者有這個意識,對自己開發的庫使用名稱空間封裝起來,避免與其他庫或者客戶程式碼發生衝突。這個只在C++語言裡面可以使用(C語言中不存在)。

2018年9月27日20:52:02