提问人:sbi 提问时间:10/13/2016 最后编辑:sbi 更新时间:8/10/2020 访问量:8482
从 C 到 C++ 再返回 bool
Getting bool from C to C++ and back
问:
在设计要通过连接 C 和 C++ 代码的 C API 传递的数据结构时,使用安全吗?也就是说,如果我有这样的:bool
struct
struct foo {
int bar;
bool baz;
};
是否保证 C(它是 )和 C++ 以相同的方式解释 的大小和含义以及它在其中的位置?baz
foo
_Bool
我们正在考虑在单个平台上执行此操作(Beaglebone 上的 Debian 8 的 GCC),C 和 C++ 代码由相同的 GCC 版本(分别为 C99 和 C++11)编译。不过,也欢迎一般性评论。
答:
C 和 C++ 的类型不同,但是,只要您坚持使用相同的编译器(在您的例子中是 gcc),它应该是安全的,因为这是一个合理的常见场景。bool
在 C++ 中,一直是一个关键字。C 直到 C99 才有一个,在那里他们引入了关键字(因为人们习惯于在 C89 代码中键入 def 或 #define as 或,因此直接添加为关键字会破坏现有代码);在 C 中,标头应该具有 typedef 或 #define from to 。看看你的;GCC 的实现如下所示:bool
_Bool
bool
int
char
bool
stdbool.h
_Bool
bool
/*
* 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 指定了这一点并遵循相同的规则。这是一个强有力的保证。我们可以得到的第三个提示是从 Objective-C 的参考手册中,它说 Objective-C 和 Objective-C++ 分别尊重 C 和 C++ 的约定,并且是等效的;所以我几乎可以说,虽然标准不能保证这一点,但你可以假设是的,它们是等价的。_Bool
bool
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
是兼容的。
评论
bool
_Bool
#ifndef bool /**/ typedef int bool; /**/ #endif
bool
bool
语言标准对此只字未提(我很高兴被证明是错的,我找不到任何东西),所以如果我们只是将自己限制在语言标准上,那就不安全了。但是,如果您对支持的架构很挑剔,您可以找到他们的 ABI 文档,看看它是否安全。
例如,amd64 ABI 文档的类型有一个脚注,内容如下:_Bool
此类型在 C++ 中称为 bool。
我无法以任何其他方式解释它,只能说它是兼容的。
另外,只是沉思一下。当然会起作用。编译器生成的代码既遵循 ABI,又遵循平台最大编译器的行为(如果该行为在 ABI 之外)。C++ 的一大优点是它可以链接到用 C 编写的库,关于库的一件事是它们可以由同一平台上的任何编译器编译(这就是为什么我们首先有 ABI 文档)。在某些时候会有一些轻微的不兼容吗?当然可以,但最好通过向编译器制造商报告错误来解决此问题,而不是在代码中解决此问题。我怀疑 bool 会是编译器制造商会搞砸的东西。
C标准唯一说的是:_Bool
声明为 type 的对象足够大,可以存储值 0 和 1.
_Bool
这意味着至少或更大(因此/保证是可存储的)。_Bool
sizeof(char)
true
false
确切的大小是Michael在评论中所说的所有实现。你最好只是在相关的编译器上对它们的大小执行一些测试,如果这些测试匹配并且你坚持使用同一个编译器,我认为它是安全的。
评论
sizeof(char)
正如 Gill Bates 上面所说,在 C 语言中,你确实遇到了一个依赖于编译器的问题。不能保证同一个编译器在 C 和 C++ 中会相同地对待它,或者它们在不同的架构上会相同。编译器甚至有权(根据 C 标准)将其表示为位域中的单个位,如果它愿意的话。sizeof(bool)
我个人在使用 TI OMAP-L138 处理器时体验过这种情况,该处理器在同一器件上结合了 32 位 ARM 内核和 32 位 DSP 内核,两者都可以访问一些共享内存。ARM 内核表示为(此处为 32 位),而 DSP 表示为(8 位)。为了解决这个问题,我定义了自己的类型以用于共享内存接口,因为我知道 32 位值对双方都有效。当然,我可以将其定义为 8 位值,但我认为如果我将其保留为本机整数大小,则不太可能影响性能。bool
int
bool
char
bool32_t
如果你和我做同样的事情,那么你可以100%保证你的C和C++代码之间的二进制兼容性。如果你不这样做,那么你就不能。就这么简单。使用相同的编译器,您的几率非常高 - 但无法保证,并且更改编译器选项很容易以意想不到的方式搞砸您。
在相关主题上,您还应该使用 ,或其他定义大小的整数。(应包括这些类型定义。在同一平台上,C和C++不太可能有所不同,但是对于固件来说,这是代码的味道。例外情况是,在你真的不在乎 an 有多长的地方,但应该清楚的是,接口和结构必须有明确的定义。对于程序员来说,对它的大小做出假设(通常是不正确的!)太容易了,而且当它出错时,结果通常是灾难性的——更糟糕的是,它们在测试中通常不会出错,因为你可以很容易地找到并修复它们。int
int16_t
int32_t
stdint.h
int
int
评论
sizeof(bool) == 1
上一个:何时使用哪种指针?
评论
sizeof(bool)
和 (C99 布尔值) 取决于实现。如果它们在你的平台上与一组给定的编译器的大小相同,我认为只要你坚持使用该编译器就是安全的。关于结构布局的填充,即使布尔类型的大小相同,这也可能是另一回事。sizeof(_Bool)
bool
的大小从 32 位更改为 8 位。因此,从理论上讲,您应该确保永远不要混合来自不同编译器版本的目标代码。OTOH,任何现代编译器都不太可能使用大于 8 位的任何内容。