在设计要通过连接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或#定义bool为int或char在C89代码,所以直接添加bool为关键字会破坏现有的代码); 有报头stdbool.h应,在C,具有从一个typedef或#定义_Bool到bool.看看你的; 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.在下面的评论指出)在许多平台,指定_Bool并bool遵循相同的规则.这是一个强烈的保证.第三提示我们可以得到从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,这_Bool和bool兼容,两者都是大小为1,对准1,代表机器的无符号字节.所以问题的答案,在Beaglebone上,是的,_Bool并且bool兼容.
Art*_*Art 15
语言标准对此没有任何说明(我很高兴被证明是错误的,我找不到任何东西),所以如果我们仅仅局限于语言标准就不安全.但是,如果您对自己支持的架构感到挑剔,可以找到他们的ABI文档,看看它是否安全.
例如,amd64 ABI文档的脚注_Bool类型为:
这种类型在C++中称为bool.
我不能以任何其他方式解释它将兼容.
而且,只是沉思这一点.当然会有效.编译器生成的代码都遵循ABI和平台最大编译器的行为(如果该行为在ABI之外).关于C++的一个重要的事情是它可以链接到用C编写的库,而关于库的事情是它们可以由同一平台上的任何编译器编译(这就是我们首先拥有ABI文档的原因).在某些时候可能存在一些轻微的不兼容性吗?当然,但是通过向编译器制造商提供的错误报告而不是代码中的解决方法,您可以更好地解决这个问题.我怀疑bool是编译器制造商会搞砸的东西.
C标准唯一说的是_Bool:
声明为type的对象
_Bool足以存储值0和1.
这将意味着_Bool是至少 sizeof(char)或更大(因此true/ false保证是可存储).
确切的大小是迈克尔在评论中所说的所有实现.你最好只在相关的编译器上对它们的大小进行一些测试,如果那些匹配并且你坚持使用相同的编译器,我认为它是安全的.
正如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,但应该清楚接口和结构必须有明确的定义.程序员很容易做出关于其大小的假设(通常是不正确的!),并且当出错时结果通常是灾难性的 - 更糟糕的是,他们在测试中通常不会出错,您可以轻松找到并修复他们.