从C到C ++获得bool并返回

时间:2016-10-13 12:00:36

标签: c++ c

在设计要通过连接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)。不过, 一般评论 也是受欢迎的。

4 个答案:

答案 0 :(得分:45)

C和C ++的bool类型不同,但是,只要你坚持使用相同的编译器(在你的情况下,gcc),它应该是安全的,因为这是一个合理的常见情况。

在C ++中,bool一直是关键字。 C在C99之前没有一个,他们在那里引入了关键字_Bool(因为人们曾经在C89代码中将typedef或#define bool设置为intchar,所以直接添加bool作为关键字会破坏现有代码);标题stdbool.h应该在C中具有从_Boolbool的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 ABIwhich is used by GCC和大多数其他编译器(Visual Studio除外; Matthieu M.在下面的评论中指出)指定_Bool并且bool遵循相同的规则。这是一个强烈的保证。我们可以得到的第三个提示来自Objective-C's reference manual,它表示对于分别遵守C和C ++惯例的Objective-C和Objective-C ++,bool_Bool是等价的;所以我会说,虽然标准不保证这一点,你可以假设是的,它们是等价的。

编辑:

如果标准不保证_Boolbool兼容(大小,对齐和填充),那会是什么?

当我们说那些东西是“架构依赖”时,我们实际上意味着它们 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上,是,_Boolbool是兼容的

答案 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_tint32_t或其他已定义大小的整数。 (对于这些类型定义,您应该包括stdint.h。)在同一平台上,C和C ++的可能性不大,但使用int的固件代码味道很大。例外情况是你真正不关心int有多长的地方,但应该清楚接口和结构 必须 具有以下优点:定义。程序员很容易做出关于其大小的假设(通常是不正确的!),并且当出错时结果通常是灾难性的 - 更糟糕的是,他们在测试中通常不会出错,您可以轻松找到并修复它们。