[英]Getting bool from C to C++ and back
在設計要通過連接 C 和 C++ 代碼的 C API 傳遞的數據結構時,使用bool
是否安全? 也就是說,如果我有這樣的struct
:
struct foo {
int bar;
bool baz;
};
是否保證baz
的大小和含義以及它在foo
中的位置由 C(它是_Bool
)和 C++ 以相同的方式解釋?
我們正在考慮在單個平台(Beaglebone 上的 Debian 8 的 GCC)上執行此操作,其中 C 和 C++ 代碼由相同的 GCC 版本(分別為 C99 和 C++11)編譯。 不過,也歡迎一般性評論。
C 和 C++ 的bool
類型不同,但是,只要您堅持使用相同的編譯器(在您的情況下,gcc),它應該是安全的,因為這是一個合理的常見場景。
在 C++ 中, bool
一直是一個關鍵字。 C 直到 C99 才擁有一個,在那里他們引入了關鍵字_Bool
(因為人們習慣於在 C89 代碼中 typedef 或 #define bool
為int
或char
,因此直接添加bool
作為關鍵字會破壞現有代碼); 頭文件stdbool.h
在 C 中應該有一個 typedef 或 #define 從_Bool
到bool
。 看看你的; GCC 的實現如下所示:
/*
* ISO C Standard: 7.16 Boolean type and values <stdbool.h>
*/
#ifndef _STDBOOL_H
#define _STDBOOL_H
#ifndef __cplusplus
#define bool _Bool
#define true 1
#define false 0
#else /* __cplusplus */
/* Supporting <stdbool.h> in C++ is a GCC extension. */
#define _Bool bool
#define bool bool
#define false false
#define true true
#endif /* __cplusplus */
/* Signal that all the definitions are present. */
#define __bool_true_false_are_defined 1
#endif /* stdbool.h */
這讓我們相信,至少在 GCC 中,這兩種類型是兼容的(在大小和對齊方式上,因此結構布局將保持不變)。
同樣值得注意的是, GCC和大多數其他編譯器(Visual Studio 除外;正如 Matthieu M. 在下面的評論中指出的)在許多平台上使用的Itanium ABI指定_Bool
和bool
遵循相同的規則。 這是一個強有力的保證。 我們可以得到的第三個提示來自Objective-C 的參考手冊,它說對於分別尊重 C 和 C++ 約定的 Objective-C 和 Objective-C++, bool
和_Bool
是等效的; 所以我幾乎可以說,雖然標准不保證這一點,但您可以假設是的,它們是等效的。
如果標准不保證_Bool
和bool
將兼容(在大小、對齊和填充方面),那該怎么辦?
當我們說這些東西“依賴於架構”時,我們實際上是指它們依賴於 ABI 。 每個編譯器實現一個或多個 ABI,如果兩個編譯器(或同一編譯器的版本)實現相同的 ABI,則稱它們兼容。 由於預期從 C++ 調用 C 代碼,因為這無處不在,所以我聽說過的所有 C++ ABI 都擴展了本地 C ABI。
由於 OP 詢問了 Beaglebone,因此我們必須檢查ARM ABI ,尤其是 Debian 使用的 GNU ARM EABI。 正如 Justin Time 在評論中所指出的, ARM ABI 確實聲明了 C++ 的 ABI 來擴展 C 的,並且_Bool
和bool
是兼容的,兩者都是大小為 1,對齊為 1,代表機器的無符號字節。 所以這個問題的答案,在 Beaglebone 上,是的, _Bool
和bool
是兼容的。
語言標准對此沒有任何說明(我很高興被證明是錯誤的,我找不到任何東西),因此如果我們只將自己限制在語言標准上,那是不安全的。 但是,如果您對支持的架構很挑剔,您可以找到他們的 ABI 文檔,看看它是否安全。
例如, amd64 ABI 文檔有一個_Bool
類型的腳注,它說:
這種類型在 C++ 中稱為 bool。
除了它將兼容之外,我無法以任何其他方式解釋它。
另外,只是在思考這個。 當然會起作用。 編譯器生成的代碼既遵循 ABI 又遵循平台最大編譯器的行為(如果該行為在 ABI 之外)。 C++ 的一大特點是它可以鏈接到用 C 編寫的庫,而庫的一個特點是它們可以被同一平台上的任何編譯器編譯(這就是我們首先擁有 ABI 文檔的原因)。 在某些時候會出現一些輕微的不兼容嗎? 當然,但這是您最好通過向編譯器制造商報告錯誤而不是在您的代碼中解決方法來解決的問題。 我懷疑 bool 會不會是編譯器制造商會搞砸的東西。
C 標准在_Bool
說的唯一內容:
聲明為
_Bool
類型的對象足夠大,可以存儲值 0 和 1。
這意味着_Bool
至少是sizeof(char)
或更大(所以true
/ false
保證是可存儲的)。
確切的大小是邁克爾在評論中所說的所有實現。 你最好只在相關編譯器上對它們的大小執行一些測試,如果這些匹配並且你堅持使用同一個編譯器,我認為它是安全的。
正如上面 Gill Bates 所說,你確實有一個問題,即sizeof(bool)
在 C 中是依賴於編譯器的。不能保證相同的編譯器在 C 和 C++ 中會以相同的方式對待它,或者它們在不同的體系結構上會相同. 如果需要,編譯器甚至有權(根據 C 標准)將其表示為位域中的單個位。
我在使用 TI OMAP-L138 處理器時親身經歷過這種情況,該處理器在同一設備上結合了 32 位 ARM 內核和 32 位 DSP 內核,並且兩者都可以訪問一些共享內存。 ARM 內核將bool
表示為int
(此處為 32 位),而 DSP 將bool
表示為char
(8 位)。 為了解決這個問題,我定義了自己的類型bool32_t
用於共享內存接口,因為知道 32 位值對雙方都適用。 當然,我可以將其定義為 8 位值,但我認為如果將其保留為本機整數大小,則不太可能影響性能。
如果你像我一樣做,那么你可以 100% 保證你的 C 和 C++ 代碼之間的二進制兼容性。 如果你不這樣做,你就不能。 就這么簡單。 使用相同的編譯器,您的勝算很大 - 但不能保證,更改編譯器選項很容易以意想不到的方式讓您失望。
在相關主題上,您的int
也應該使用int16_t
、 int32_t
或另一個定義大小的整數。 (您應該為這些類型定義包含stdint.h
。)在同一平台上,C 和 C++ 的情況不太可能不同,但固件使用int
是一種代碼味道。 例外是在您真正不關心int
有多長的地方,但應該清楚接口和結構必須具有明確定義。 程序員很容易對它的大小做出假設(這通常是不正確的!),當它出錯時結果通常是災難性的——更糟糕的是,他們在測試中通常不會出錯,你可以很容易地找到並修復他們。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.