在设计要通过连接C和C ++代码的C API传递的数据结构时,使用bool
是否安全?也就是说,如果我有struct
这样的话:
struct foo {
int bar;
bool baz;
};
是否保证baz
的大小和含义以及foo
中的位置在C中以相同的方式解释(其中' sa _Bool
)和通过C ++?
我们正在考虑在单个平台上执行 (Beaglebone上的Debian 8的GCC),其中C和C ++代码由相同的GCC版本编译(如分别是C99和C ++ 11)。不过, 一般评论 也是受欢迎的。
答案 0 :(得分:45)
C和C ++的bool
类型不同,但是,只要你坚持使用相同的编译器(在你的情况下,gcc),它应该是安全的,因为这是一个合理的常见情况。
在C ++中,bool
一直是关键字。 C在C99之前没有一个,他们在那里引入了关键字_Bool
(因为人们曾经在C89代码中将typedef或#define bool
设置为int
或char
,所以直接添加bool
作为关键字会破坏现有代码);标题stdbool.h
应该在C中具有从_Bool
到bool
的typedef或#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 */
这使我们相信,至少在GCC中,这两种类型是兼容的(在大小和对齐方面,所以结构布局将保持不变)。
另外值得注意的是,许多平台上的Itanium ABI,which is used by GCC和大多数其他编译器(Visual Studio除外; Matthieu M.在下面的评论中指出)指定_Bool
并且bool
遵循相同的规则。这是一个强烈的保证。我们可以得到的第三个提示来自Objective-C's reference manual,它表示对于分别遵守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 indeed declares C++'s ABI to extend C's, and that _Bool
and bool
are compatible,大小为1,对齐1,表示机器的无符号字节。所以问题的答案,在Beaglebone上,是,_Bool
和bool
是兼容的。
答案 1 :(得分:15)
语言标准对此没有任何说明(我很高兴被证明是错误的,我找不到任何东西),所以如果我们仅限于语言标准就不安全。但是,如果您对自己支持的架构感到挑剔,可以找到他们的ABI文档,看看它是否安全。
例如,amd64 ABI document有一个_Bool
类型的脚注,上面写着:
这种类型在C ++中称为bool。
我不能以任何其他方式解释它将是兼容的。
另外,只是沉思这一点。当然会有效。编译器生成的代码都遵循ABI和平台最大编译器的行为(如果该行为在ABI之外)。关于C ++的一个重要的事情是它可以链接到用C编写的库,而关于库的事情是它们可以由同一平台上的任何编译器编译(这就是我们首先拥有ABI文档的原因)。在某些时候可能存在一些轻微的不兼容性吗?当然,但是通过向编译器制造商提供的错误报告而不是代码中的解决方法,您可以更好地解决这个问题。我怀疑bool是编译器制造商会搞砸的东西。
答案 2 :(得分:6)
C标准在[OperationContract]
[WebInvoke(Method = "POST",
RequestFormat = WebMessageFormat.Json,
ResponseFormat = WebMessageFormat.Json,
UriTemplate = "Test")]
bool Test(OrderReprint oreprints);
上唯一说的是:
声明为类型
_Bool
的对象足以存储值0 和1。
这意味着_Bool
至少 _Bool
或更高(因此sizeof(char)
/ true
可以保证存储。)< / p>
确切的大小是迈克尔在评论中所说的所有实现。你最好只在相关的编译器上对它们的大小进行一些测试,如果那些匹配并且你坚持使用相同的编译器,我认为它是安全的。
答案 3 :(得分:5)
正如Gill Bates所说,你确实遇到sizeof(bool)
依赖于编译器的问题。不能保证相同的编译器会对它进行相同的处理。如果为枚举定义的值可以适合较小的位数,编译器通常可以选择减少枚举的长度,bool
以这种方式处理也不会出乎意料。如果需要,编译器甚至可以在其权限范围内(根据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
有多长的地方,但应该清楚接口和结构 必须 具有以下优点:定义。程序员很容易做出关于其大小的假设(通常是不正确的!),并且当出错时结果通常是灾难性的 - 更糟糕的是,他们在测试中通常不会出错,您可以轻松找到并修复它们。