繁体   English   中英

从 C 到 C++ 并返回布尔值

[英]Getting bool from C to C++ and back

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

struct foo {
  int bar;
  bool baz;
};

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

我们正在考虑在单个平台(Beaglebone 上的 Debian 8 的 GCC)上执行此操作,其中 C 和 C++ 代码由相同的 GCC 版本(分别为 C99 和 C++11)编译。 不过,也欢迎一般性评论

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

在 C++ 中, bool一直是一个关键字。 C 直到 C99 才拥有一个,在那里他们引入了关键字_Bool (因为人们习惯于在 C89 代码中 typedef 或 #define boolintchar ,因此直接添加bool作为关键字会破坏现有代码); 头文件stdbool.h在 C 中应该有一个 typedef 或 #define 从_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 */

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

同样值得注意的是, GCC和大多数其他编译器(Visual Studio 除外;正如 Matthieu M. 在下面的评论中指出的)在许多平台上使用Itanium ABI指定_Boolbool遵循相同的规则。 这是一个强有力的保证。 我们可以得到的第三个提示来自Objective-C 的参考手册,它说对于分别尊重 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 确实声明了 C++ 的 ABI 来扩展 C 的,并且_Boolbool是兼容的,两者都是大小为 1,对齐为 1,代表机器的无符号字节。 所以这个问题的答案,在 Beaglebone 上,是的, _Boolbool是兼容的

语言标准对此没有任何说明(我很高兴被证明是错误的,我找不到任何东西),因此如果我们只将自己限制在语言标准上,那是不安全的。 但是,如果您对支持的架构很挑剔,您可以找到他们的 ABI 文档,看看它是否安全。

例如, amd64 ABI 文档有一个_Bool类型的脚注,它说:

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

除了它将兼容之外,我无法以任何其他方式解释它。

另外,只是在思考这个。 当然会起作用。 编译器生成的代码既遵循 ABI 又遵循平台最大编译器的行为(如果该行为在 ABI 之外)。 C++ 的一大特点是它可以链接到用 C 编写的库,而库的一个特点是它们可以被同一平台上的任何编译器编译(这就是我们首先拥有 ABI 文档的原因)。 在某些时候会出现一些轻微的不兼容吗? 当然,但这是您最好通过向编译器制造商报告错误而不是在您的代码中解决方法来解决的问题。 我怀疑 bool 会不会是编译器制造商会搞砸的东西。

C 标准在_Bool说的唯一内容:

声明为_Bool类型的对象足够大,可以存储值 0 和 1。

这意味着_Bool至少是sizeof(char)或更大(所以true / false保证是可存储的)。

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

正如上面 Gill Bates 所说,你确实有一个问题,即sizeof(bool)在 C 中是依赖于编译器的。不能保证相同的编译器在 C 和 C++ 中会以相同的方式对待它,或者它们在不同的体系结构上会相同. 如果需要,编译器甚至有权(根据 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有多长的地方,但应该清楚接口和结构必须具有明确定义。 程序员很容易对它的大小做出假设(这通常是不正确的!),当它出错时结果通常是灾难性的——更糟糕的是,他们在测试中通常不会出错,你可以很容易地找到并修复他们。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM