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

sbi*_*sbi 47 c c++

在设计要通过连接C和C++代码的C API传递的数据结构时,使用它是否安全bool?也就是说,如果我有struct这样的:

struct foo {
  int bar;
  bool baz;
};
Run Code Online (Sandbox Code Playgroud)

是否保证C的大小和含义baz以及它的位置foo由C(它是a _Bool)和C++ 以相同的方式解释?

我们正在考虑在一个平台上进行此操作(在Beaglebone上使用GCC for Debian 8),C和C++代码由相同的GCC版本(分别为C99和C++ 11)编译.不过,欢迎提出一般性意见.

pau*_*ens 45

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

在C++中,bool一直是关键字.Ç没有一个直到C99,在那里他们推出了关键字_Bool(因为人们使用的typedef或#定义boolintchar在C89代码,所以直接添加bool为关键字会破坏现有的代码); 有报头stdbool.h应,在C,具有从一个typedef或#定义_Boolbool.看看你的; 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 */
Run Code Online (Sandbox Code Playgroud)

这使我们相信,至少在GCC中,这两种类型是兼容的(在大小和对齐方面,因此结构布局将保持不变).

还值得一提的安腾ABI,其通过使用GCC和大多数其他的编译器(除了Visual Studio中;如马修M.在下面的评论指出)在许多平台,指定_Boolbool遵循相同的规则.这是一个强烈的保证.第三提示我们可以得到从Objective-C的参考手册,其中说,对目标C和Objective-C++,它们分别尊重C'S和C++的约定,bool_Bool是等效的; 所以我会说,虽然标准不能保证这一点,但你可以认为是的,它们是等价的.

编辑:

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

当我们说这些东西是" 依赖于架构的 "时,我们实际上意味着它们依赖于ABI.每个编译器实现一个或多个ABI,如果它们实现相同的ABI,则称两个编译器(或相同编译器的版本)是兼容的.由于预期从C++调用C代码,因为这种情况无处不在,所以我听说过的所有C++ ABI都扩展了本地C ABI.

由于OP询问了Beaglebone,我们必须检查ARM ABI,特别是Debian使用的GNU ARM EABI.正如由Justin时间在评论中指出的那样,ARM ABI确实宣称C++的ABI扩展C'S,这_Boolbool兼容,两者都是大小为1,对准1,代表机器的无符号字节.所以问题的答案,在Beaglebone上,是的,_Bool并且bool兼容.

  • 如果我找到一个既支持C和C++但又实现了`bool`和`_Bool`的编译器,我会找到它的程序员,我会找到它们,我会坐下来向他们解释为什么他们这是一个巨大的错误. (23认同)
  • @Heshy,我认为这是因为一些遗留程序会检查`#ifndef bool/**/typedef int bool;/**/#endif`或类似的东西.实际上我已经看起来已经疯狂了.如果`bool`不是#defined到`bool`,这样的代码就会失败. (13认同)
  • 如果C代码和C++代码都编译为C++(使用g ++),gcc的实现只提供兼容性.它不提供实际编译为C的C代码与C++代码之间的兼容性. (8认同)
  • 我将更多地强调Itanium ABI:这是除了Visual Studio之外所有主要C++播放器实现的ABI,这意味着兼容性不仅保证在单个版本的GCC中,它实际上保证*在编译器和版本*之间,它也是*包括未来版本*.很难找到更好的保证.但是......值得链接到ABI提到这一点的具体部分; 我发现https://mentorembedded.github.io/cxx-abi/abi.html#pod这是你在想什么? (5认同)
  • 为什么他们打扰#define bool bool #define false false #define true true(在#else部分)? (5认同)
  • ARM ABI指定["bool`的C99语义旨在匹配C++的语义."](http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc. dui0375g/chr1359124241645.html),文档的其他部分表明`sizeof(bool)== sizeof(_Bool)== sizeof(char)`(8位)和`alignof(bool)== alignof(_Bool)= = alignof(char)`(1个字节).从这一点来看,假设C`_Bool`和C++`bool`在ARM上是等价的,这是可能的. (3认同)
  • @Heshy这似乎是一个GCC修改,允许但不是必需的.正式地说,C++ 11标题`cstdbool`(C的`stdbool.h`的C++版本)只包含宏`#define __bool_true_false_are_defined 1`,因为`bool`,`true`和`false`已被定义为关键字.因此,对于C++来说,GCC似乎将它们定义为扩展为相同拼写关键字的宏.[通过使编译器为您提供重新定义警告,这也可以提供任何其他C头定义为宏的安全措施.] (2认同)
  • @paulotorrens _"我不知道你是谁.我不知道你想要什么.如果你正在寻找赎金,我可以告诉你我没有钱,但我所拥有的是一套特别的技能.我在很长的职业生涯中获得的技能.让我成为像你这样的人的噩梦的技能.如果你现在修复你的编译器就会结束它.我不会找你,我不会追你,但如果你不这样做,我会找你,我会找到你,我会毫不含糊地向你解释你的错误."_ (2认同)

Art*_*Art 15

语言标准对此没有任何说明(我很高兴被证明是错误的,我找不到任何东西),所以如果我们仅仅局限于语言标准就不安全.但是,如果您对自己支持的架构感到挑剔,可以找到他们的ABI文档,看看它是否安全.

例如,amd64 ABI文档的脚注_Bool类型为:

这种类型在C++中称为bool.

我不能以任何其他方式解释它将兼容.

而且,只是沉思这一点.当然会有效.编译器生成的代码都遵循ABI和平台最大编译器的行为(如果该行为在ABI之外).关于C++的一个重要的事情是它可以链接到用C编写的库,而关于库的事情是它们可以由同一平台上的任何编译器编译(这就是我们首先拥有ABI文档的原因).在某些时候可能存在一些轻微的不兼容性吗?当然,但是通过向编译器制造商提供的错误报告而不是代码中的解决方法,您可以更好地解决这个问题.我怀疑bool是编译器制造商会搞砸的东西.


Som*_*ken 6

C标准唯一说的是_Bool:

声明为type的对象_Bool足以存储值0和1.

这将意味着_Bool至少 sizeof(char)或更大(因此true/ false保证是可存储).

确切的大小是迈克尔在评论中所说的所有实现.你最好只在相关的编译器上对它们的大小进行一些测试,如果那些匹配并且你坚持使用相同的编译器,我认为它是安全的.

  • 但是`sizeof(char)`保证是1.每种类型等于或大于该类型. (2认同)

Gra*_*ham 5

正如Gill Bates上面所说,你确实遇到了sizeof(bool)依赖于编译器的问题.不能保证相同的编译器会对它进行相同的处理.如果为枚举定义的值可以适合较小的位数,编译器通常可以选择减少枚举的长度,并且bool以这种方式处理也不会出乎意料.如果需要,编译器甚至可以在其权限内(根据C标准)将其表示为位域中的单个位.

我个人在使用TI OMAP-L138处理器时遇到过这种情况,该处理器在同一设备上结合了32位ARM内核和32位DSP内核,并且两者都可以访问一些共享内存.ARM内核表示boolint(此处为32位),而DSP表示boolchar(8位).为了解决这个问题,我将自己的类型定义bool32_t为与共享内存接口一起使用,知道32位值对双方都有效.当然我可以将其定义为8位值,但我认为如果将其保留为原生整数大小,则不太可能影响性能.

如果你像我一样做,那么你可以100%保证你的C和C++代码之间的二进制兼容性.如果你不这样做,你就不能.它真的很简单.使用相同的编译器,您的几率非常好 - 但无法保证,更改编译器选项可能会以意想不到的方式轻易搞砸.

在一个相关的主题,你int也应该使用int16_t,int32_t或定义大小的另一个整数.(您应该包括stdint.h这些类型定义.)在同一平台上,C和C++的可能性不大,但它是固件使用的代码味道int.例外情况是你真正不关心多长时间int,但应该清楚接口和结构必须有明确的定义.程序员很容易做出关于其大小的假设(通常是不正确的!),并且当出错时结果通常是灾难性的 - 更糟糕的是,他们在测试中通常不会出错,您可以轻松找到并修复他们.