2011-12-18 63 views
5

我有一個編譯到庫(dll,靜態庫等)的代碼。我希望這個庫的用戶使用一些結構來傳遞一些數據作爲庫函數的參數。我想過在API頭文件中聲明結構。庫的頭文件中的結構定義和編譯差異

  • 考慮到不同編譯器的彙編,關於結構對齊或我沒有考慮過的其他事情,這樣做是否安全?
  • 是否需要爲庫及其用戶使用相同的編譯器(和標誌)?

幾點注意事項:

  1. 我認爲通過功能給用戶一個指針,並設置所有的結構在庫中,但這樣會使API真的不舒服。
  2. 這個問題是關於C,雖然它會很高興知道是否有不同的C++。

回答

2

如果是常規/靜態庫,庫和應用程序應該使用相同的編譯器進行編譯。有幾個原因可以考慮:

  1. 不同的編譯器(如不同品牌或不同平臺的編譯器)通常不瞭解彼此的對象和庫格式。
  2. 你不想編譯使用不同類型(例如signed或unsigned char)的相同程序的不同部分,字體大小(例如long = 32和64位),對齊和打包以及其他一些東西,所有C標準允許改變。混合和匹配這些東西通常是一件壞事。

但是,您可能經常使用稍微不同的相同編譯器版本來編譯庫和使用它的應用程序。通常情況下,沒關係。不過,有時會發生破壞代碼的更改。

您可以在該頭文件中聲明一些「初始化」函數(聲明爲static inline),以確保類型,類型大小,對齊和打包與編譯庫預期的相同。使用這個庫的應用程序必須在使用庫的任何其他部分之前調用此函數。如果事情與預期不一致,則該功能必須失敗並導致程序終止,可能會對失敗進行一些良好的文本描述。這不會完全解決編譯器有點不兼容的問題,但它可以防止無聲和神祕的故障。有些事情可以通過預處理器的#if#ifdef指令進行檢查,並導致編譯錯誤#error

另外,通過在結構聲明中插入明確的填充字節並強制緊縮(例如通過例如縮放)來緩解結構填充問題。使用#pragma pack,這是由許多編譯器支持)。這樣,如果字體大小相同,則默認打包的內容無關緊要。

您也可以將相同的應用程序應用於DLL,但您應該確實希望調用的應用程序已使用不同的編譯器進行編譯,而不依賴於相同的編譯器。

+0

感謝您的詳細解答。你給了我一些新的想法。 – MByD 2011-12-18 05:54:19

0

所有的Windows APIs都像瘋了一樣拋出結構,所以顯然這是每天都會完成的工作。當然,這並不意味着你的擔心是無效的:) 我會建議讓你的結構的字段有明確的寬度類型(int32_t等),也許明確指出,打包的方式會破壞任何編譯器,但你的,即

#if defined(_MSC_VER) 
#pragma pack(0) 
#elif defined ... handle gcc 
#else 
FAIL // fail compilation on unsupported platform 
#endif 
+0

Windows APIs *明確*明確地爲其結構定義打包。他們只是封裝/混淆了所有的標題。你很可能*安全地做到這一點,但徹底鼓勵行使護理。 – 2011-12-18 05:15:08

+0

gcc支持#pragma pack。 – 2011-12-18 05:28:32