从C到C ++的bool和回来
在devise要通过连接C和C ++代码的C API的数据结构时,使用bool
是否安全? 也就是说,如果我有这样的struct
:
struct foo { int bar; bool baz; };
是否保证了baz
的大小和含义以及它在foo
中的位置是以C(它是一个_Bool
)还是由C ++来解释的?
我们正考虑在同一个GCC版本(分别为C99和C ++ 11)上编译C和C ++代码的单一平台上 (GCC在Beaglebone上使用Debian 8)。 一般的意见也是受欢迎的,但是。
C和C ++的bool
types是不同的,但是,只要你坚持使用相同的编译器(在你的情况下,gcc),它应该是安全的,因为这是一个合理的常见的情况。
在C ++中, bool
一直是关键字。 C没有一个,直到C99,他们介绍了关键字_Bool
(因为人们曾经在C89代码中键入def或#define bool
int
或char
,所以直接添加bool
作为关键字会破坏现有的代码)。 头文件stdbool.h
应该在C中有一个typedef或从_Bool
到bool
#define。 看看你的; 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 */
这导致我们相信,至less在GCC中,这两种types是兼容的(在大小和alignment方面,所以结构布局将保持不变)。
另外值得注意的是,在许多平台上, GCC和大多数其他编译器(除了Visual Studio; Matthieu M.在下面的注释中指出)使用的Itanium ABI指定_Bool
和bool
遵循相同的规则。 这是一个强大的保证。 我们可以从Objective-C的参考手册得到第三个提示,那就是Objective-C和Objective-C ++分别遵循C和C ++的约定, bool
和_Bool
是等价的; 所以我几乎可以这么说,虽然标准不能保证这一点,但你可以假设是的,它们是等价的。
编辑:
如果标准不能保证_Bool
和bool
将兼容(在大小,alignment和填充),什么?
当我们说这些东西是“ build筑依赖 ”时,我们实际上是指它们是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的alignment1,表示一个机器的无符号字节。 所以这个问题的答案在Beaglebone上, 是的, _Bool
和bool
是兼容的 。
语言标准对此没有任何规定(我很高兴被certificate是错误的,我找不到任何东西),所以如果我们仅仅限于语言标准就不可能是安全的。 但如果您挑剔您支持的架构,您可以find他们的ABI文件,看看它是否安全。
例如, amd64 ABI文档有一个_Bool
types的脚注,它说:
这种types在C ++中被称为bool。
我不能以任何其他方式来解释它将是兼容的。
此外,只是沉思这一点。 当然,它会工作。 编译器生成的代码都遵循ABI以及该平台最大编译器的行为(如果该行为在ABI之外)。 关于C ++的一件大事就是它可以链接到用C编写的库,关于库的一个事情是它们可以被同一平台上的任何编译器编译(这就是为什么我们有ABI文档的原因)。 在某些时候会有一些小的不兼容性吗? 当然,但这是你最好通过编译器制造商的错误报告来解决,而不是在你的代码中解决。 我怀疑bool是编译器制造商会搞砸的东西。
C标准在_Bool
说的唯一一件事:
声明为
_Bool
types的对象的大小足以存储值0和1。
这将意味着_Bool
至less sizeof(char)
或更大(所以true
/ false
保证可存储)。
尽pipeMichael在评论中说,确切的大小是所有的实现定义。 你最好在相关的编译器上对它们的大小进行一些testing,如果那些匹配,并且坚持使用相同的编译器,我会认为它是安全的。
正如Gill Bates上面所说的,你确实有一个sizeof(bool)
依赖于编译器的问题。 不能保证相同的编译器会把它看成是一样的。 编译器通常可以select减less枚举的长度,如果为枚举定义的值可以适用于较less的位数,并且bool
被这样处理并不意外。 如果需要,编译器甚至可以在其权限范围内(根据C标准)将其表示为位字段中的单个位。
在使用TI OMAP-L138处理器时,我亲身体验过这一点,该处理器在同一器件上集成了32位ARM内核和32位DSP内核,并且可以通过两者访问某些共享内存。 ARM内核将bool
表示为int
(32位),而DSP表示bool
char
(8位)。 为了解决这个问题,我定义了我自己的typesbool32_t
以便与共享内存接口一起使用,知道一个32位值对双方都有效。 当然,我可以将它定义为一个8位的值,但是我认为如果我将它保持为本地整数大小,则不太可能影响性能。
如果你像我一样做,那么你可以100%保证你的C和C ++代码之间的二进制兼容性。 如果你不这样做,那么你不能。 这真的很简单。 使用相同的编译器,你的可能性是非常好的 – 但不能保证,并且改变编译器选项可以很容易地以意想不到的方式把你搞砸。
在一个相关的主题上,你的int
也应该使用int16_t
, int32_t
或者另外一个已定义大小的整数。 (对于这些types定义,您应该包含stdint.h
)。在同一个平台上,这对于C和C ++来说是不一样的,但是对于使用int
固件来说是一种代码异味。 例外情况是你真的不关心int
长短,但是应该清楚的是接口和结构必须有明确的定义。 程序员很容易就其大小做出假设(通常是不正确的!),结果在出错时通常是灾难性的 – 更糟糕的是,他们在testing中很容易find并修复他们。