简体   繁体   English

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

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

When designing data structures which are to be passed through a C API which connects C and C++ code, is it safe to use bool ?在设计要通过连接 C 和 C++ 代码的 C API 传递的数据结构时,使用bool是否安全? That is, if I have a struct like this:也就是说,如果我有这样的struct

struct foo {
  int bar;
  bool baz;
};

is it guaranteed that the size and meaning of baz as well as its position within foo are interpreted in the same way by C (where it's a _Bool ) and by C++?是否保证baz的大小和含义以及它在foo中的位置由 C(它是_Bool )和 C++ 以相同的方式解释?

We are considering to do this on a single platform (GCC for Debian 8 on a Beaglebone) with both C and C++ code compiled by the same GCC version (as C99 and C++11, respectively).我们正在考虑在单个平台(Beaglebone 上的 Debian 8 的 GCC)上执行此操作,其中 C 和 C++ 代码由相同的 GCC 版本(分别为 C99 和 C++11)编译。 General comments are welcome as well, though.不过,也欢迎一般性评论

C's and C++'s bool type are different, but, as long as you stick to the same compiler (in your case, gcc), it should be safe, as this is a reasonable common scenario. C 和 C++ 的bool类型不同,但是,只要您坚持使用相同的编译器(在您的情况下,gcc),它应该是安全的,因为这是一个合理的常见场景。

In C++, bool has always been a keyword.在 C++ 中, bool一直是一个关键字。 C didn't have one until C99, where they introduced the keyword _Bool (because people used to typedef or #define bool as int or char in C89 code, so directly adding bool as a keyword would break existing code); C 直到 C99 才拥有一个,在那里他们引入了关键字_Bool (因为人们习惯于在 C89 代码中 typedef 或 #define boolintchar ,因此直接添加bool作为关键字会破坏现有代码); there is the header stdbool.h which should, in C, have a typedef or #define from _Bool to bool .头文件stdbool.h在 C 中应该有一个 typedef 或 #define 从_Boolbool Take a look at yours;看看你的; GCC's implementation looks like this: 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 */

Which leads us to believe that, at least in GCC, the two types are compatible (in both size and alignment, so that the struct layout will remain the same).这让我们相信,至少在 GCC 中,这两种类型是兼容的(在大小和对齐方式上,因此结构布局将保持不变)。

Also worth noting, the Itanium ABI , which is used by GCC and most other compilers (except Visual Studio; as noted by Matthieu M. in the comments below) on many platforms, specifies that _Bool and bool follow the same rules.同样值得注意的是, GCC和大多数其他编译器(Visual Studio 除外;正如 Matthieu M. 在下面的评论中指出的)在许多平台上使用Itanium ABI指定_Boolbool遵循相同的规则。 This is a strong garantee.这是一个强有力的保证。 A third hint we can get is from Objective-C's reference manual , which says that for Objective-C and Objective-C++, which respect C's and C++'s conventions respectively, bool and _Bool are equivalent;我们可以得到的第三个提示来自Objective-C 的参考手册,它说对于分别尊重 C 和 C++ 约定的 Objective-C 和 Objective-C++, bool_Bool是等效的; so I'd pretty much say that, though the standards do not guarantee this, you can assume that yes, they are equivalent.所以我几乎可以说,虽然标准不保证这一点,但您可以假设是的,它们是等效的。

Edit:编辑:

If the standard does not guarantee that _Bool and bool will be compatible (in size, alignment, and padding), what does?如果标准不保证_Boolbool将兼容(在大小、对齐和填充方面),那该怎么办?

When we say those things are " architecture dependent ", we actually mean that they are ABI dependent .当我们说这些东西“依赖于架构”时,我们实际上是指它们依赖于 ABI Every compiler implements one or more ABIs, and two compilers (or versions of the same compiler) are said to be compatible if they implement the same ABI.每个编译器实现一个或多个 ABI,如果两个编译器(或同一编译器的版本)实现相同的 ABI,则称它们兼容。 Since it is expected to call C code from C++, as this is ubiquitously common, all C++ ABIs I've ever heard of extend the local C ABI.由于预期从 C++ 调用 C 代码,因为这无处不在,所以我听说过的所有 C++ ABI 都扩展了本地 C ABI。

Since OP asked about Beaglebone, we must check the ARM ABI , most specifically the GNU ARM EABI used by Debian.由于 OP 询问了 Beaglebone,因此我们必须检查ARM ABI ,尤其是 Debian 使用的 GNU ARM EABI。 As noted by Justin Time in the comments, the ARM ABI indeed declares C++'s ABI to extend C's, and that _Bool and bool are compatible , both being of size 1, alignment 1, representing a machine's unsigned byte.正如 Justin Time 在评论中所指出的, ARM ABI 确实声明了 C++ 的 ABI 来扩展 C 的,并且_Boolbool是兼容的,两者都是大小为 1,对齐为 1,代表机器的无符号字节。 So the answer to the question, on the Beaglebone, yes, _Bool and bool are compatible .所以这个问题的答案,在 Beaglebone 上,是的, _Boolbool是兼容的

The language standards say nothing about this (I'm happy to be proven wrong about this, I couldn't find anything), so it can't be safe if we just limit ourselves to language standards.语言标准对此没有任何说明(我很高兴被证明是错误的,我找不到任何东西),因此如果我们只将自己限制在语言标准上,那是不安全的。 But if you're picky about which architectures you support you can find their ABI documentation to see if it will be safe.但是,如果您对支持的架构很挑剔,您可以找到他们的 ABI 文档,看看它是否安全。

For example, the amd64 ABI document has a footnote for the _Bool type that says:例如, amd64 ABI 文档有一个_Bool类型的脚注,它说:

This type is called bool in C++.这种类型在 C++ 中称为 bool。

Which I can't interpret in any other way than that it will be compatible.除了它将兼容之外,我无法以任何其他方式解释它。

Also, just musing about this.另外,只是在思考这个。 Of course it will work.当然会起作用。 Compilers generate code that both follow an ABI and the behavior of the largest compiler for the platform (if that behavior is outside the ABI).编译器生成的代码既遵循 ABI 又遵循平台最大编译器的行为(如果该行为在 ABI 之外)。 A big thing about C++ is that it can link to libraries written in C and a thing about libraries is that they can be compiled by any compiler on the same platform (this is why we have ABI documents in the first place). C++ 的一大特点是它可以链接到用 C 编写的库,而库的一个特点是它们可以被同一平台上的任何编译器编译(这就是我们首先拥有 ABI 文档的原因)。 Can there be some minor incompatibility at some point?在某些时候会出现一些轻微的不兼容吗? Sure, but that's something you'd better solve by a bug report to the compiler maker rather than workaround in your code.当然,但这是您最好通过向编译器制造商报告错误而不是在您的代码中解决方法来解决的问题。 I doubt bool would be something compiler makers would screw up.我怀疑 bool 会不会是编译器制造商会搞砸的东西。

The only thing the C standard says on _Bool : C 标准在_Bool说的唯一内容:

An object declared as type _Bool is large enough to store the values 0 and 1.声明为_Bool类型的对象足够大,可以存储值 0 和 1。

Which would mean that _Bool is at least sizeof(char) or greater (so true / false are guaranteed to be storable).这意味着_Bool至少是sizeof(char)或更大(所以true / false保证是可存储的)。

The exact size is all implementation defined as Michael said in the comments though.确切的大小是迈克尔在评论中所说的所有实现。 You're better off just performing some tests on their sizes on the relevant compiler and if those match and you stick with that same compiler I'd consider it's safe.你最好只在相关编译器上对它们的大小执行一些测试,如果这些匹配并且你坚持使用同一个编译器,我认为它是安全的。

As Gill Bates says above, you do have a problem that sizeof(bool) is compiler-dependent in C. There's no guarantee that the same compiler will treat it the same in C and C++, or that they would be the same on different architectures.正如上面 Gill Bates 所说,你确实有一个问题,即sizeof(bool)在 C 中是依赖于编译器的。不能保证相同的编译器在 C 和 C++ 中会以相同的方式对待它,或者它们在不同的体系结构上会相同. The compiler would even be within its rights (according to the C standard) to represent this as an individual bit in a bitfield if it wanted.如果需要,编译器甚至有权(根据 C 标准)将其表示为位域中的单个位。

I've personally experienced this when working with the TI OMAP-L138 processor which combines a 32-bit ARM core and a 32-bit DSP core on the same device, with some shared memory accessible by both.我在使用 TI OMAP-L138 处理器时亲身经历过这种情况,该处理器在同一设备上结合了 32 位 ARM 内核和 32 位 DSP 内核,并且两者都可以访问一些共享内存。 The ARM core represented bool as an int (32-bit here), whereas the DSP represented bool as char (8-bit). ARM 内核将bool表示为int (此处为 32 位),而 DSP 将bool表示为char (8 位)。 To solve this, I defined my own type bool32_t for use with the shared memory interface, knowing that a 32-bit value would work for both sides.为了解决这个问题,我定义了自己的类型bool32_t用于共享内存接口,因为知道 32 位值对双方都适用。 Of course I could have defined it as an 8-bit value, but I considered it less likely to affect performance if I kept it as the native integer size.当然,我可以将其定义为 8 位值,但我认为如果将其保留为本机整数大小,则不太可能影响性能。

If you do the same as I did then you can 100% guarantee binary compatibility between your C and C++ code.如果你像我一样做,那么你可以 100% 保证你的 C 和 C++ 代码之间的二进制兼容性。 If you don't then you can't.如果你不这样做,你就不能。 It's really as simple as that.就这么简单。 With the same compiler, your odds are very good - but there is no guarantee, and changing compiler options can easily screw you over in unexpected ways.使用相同的编译器,您的胜算很大 - 但不能保证,更改编译器选项很容易以意想不到的方式让您失望。

On a related subject, your int should also be using int16_t , int32_t or another integer of defined size.在相关主题上,您的int也应该使用int16_tint32_t或另一个定义大小的整数。 (You should include stdint.h for these type definitions.) On the same platform it is highly unlikely that this will be different for C and C++, but it is a code smell for firmware to use int . (您应该为这些类型定义包含stdint.h 。)在同一平台上,C 和 C++ 的情况不太可能不同,但固件使用int是一种代码味道。 The exception is in places where you genuinely don't care how long an int is, but it should be clear that interfaces and structures must have that well-defined.例外是在您真正不关心int有多长的地方,但应该清楚接口和结构必须具有明确定义。 It is too easy for programmers to make assumptions (which are frequently incorrect!) about its size, and the results are generally catastrophic when it goes wrong - and worse, they often don't go wrong in testing where you can easily find and fix them.程序员很容易对它的大小做出假设(这通常是不正确的!),当它出错时结果通常是灾难性的——更糟糕的是,他们在测试中通常不会出错,你可以很容易地找到并修复他们。

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

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