向我的 C 结构体添加一个新的位域会破坏二进制兼容性吗?

问题描述 投票:0回答:1

我继承了一些在结构中使用位域的代码:

typedef _my_flags {
    unsigned int x_ida:1;
    unsigned int x_foo:6;
    unsigned int x_bar:6;
    unsigned int x_bonzo:6;
    unsigned int x_pizza:6;
    unsigned int x_jack:1;
    unsigned int x_flashed:1;
    unsigned int x_flabberghasted:1;
} t_my_flags;

typdef _my_struct {
   short cat;
   int foo, bar, bla;
   t_my_flags flags; /* ... */
   char* name;
}

两种结构都是公共 API 的一部分。

现在我迫切需要添加一些额外的标志(好吧,实际上只有一个),所以我想知道添加扩展

t_my_flags
结构是否安全:

typedef _my_flags {
    unsigned int x_ida:1;
    unsigned int x_foo:6;
    unsigned int x_bar:6;
    unsigned int x_bonzo:6;
    unsigned int x_pizza:6;
    unsigned int x_jack:1;
    unsigned int x_flashed:1;
    unsigned int x_flabberghasted:1;
    unsigned int x_ready:1; /* new member */
} t_my_flags;

编辑这些结构在动态库中使用(所以不要担心将数据保存在文件系统上或通过网络发送)

我担心破坏二进制兼容性。

我的更改会将

t_my_flags
结构从 28 位增加到 29 位,所以我假设它无论如何都会存在于 32 位整数中。 所以结构的总大小不会改变。

OTOH,我不知道标志字段的顺序是否会改变......

当然,这应该可以在所有主要操作系统(Linux、macOS、Windows)上使用未知编译器(显然是 gcc/clang 和 MSVC,不知道其他人;我们坚持使用 C89 是有原因的……)。

EDIT 我们可能假设在任何给定的操作系统/体系结构上都使用相同的编译器(好吧,对于 Windows,我们使用 gcc 的

-mms-bitfields
标志,这应该使我们与 MSVC 的位域兼容)。 上面给出的体系结构/操作系统/编译器列表仅表示我对我的用例在不同环境中的行为感兴趣。我不太关心不同环境之间的互操作性)。

那么:就二进制兼容性而言,如何在不改变整体大小的情况下添加新的位域?

c bit-fields binary-compatibility
1个回答
2
投票

向我的 C 结构体添加一个新的位域会破坏 ABI 吗?

ABI 是环境的属性,而不是您的程序或库的属性。我想你的意思是问你的改变是否会破坏二进制兼容性,这是不同的。

既然你说...

两种结构都是公共 API 的一部分。

...我推断代码是共享库的一部分(不是静态库)。这确实是二进制兼容性相关的主要情况之一,因为对于大多数其他目的,二进制兼容性是由以下事实引起的:除非您重新编译它,否则其他代码将看不到任何此类更改。

基本的答案是“视情况而定”,但更诚实的答案是“可能如此”,最安全的解释是“是”。

我的更改会将

t_my_flags
结构从 28 位增加到 29 位,所以我假设它无论如何都会存在于 32 位整数中。所以结构的总大小不会改变。

一般来说,这是一个可能的结果,但绝不是保证的结果。这是目标系统的 ABI 可以解决的问题之一。

OTOH,我不知道标志字段的顺序是否会改变......

同样,相关的 ABI 会告诉你结构布局的细节,包括位域。 C 语言规范对此没有太多说明,但确实提供了其他标志的位置在其可寻址存储单元内发生变化的可能性。同样,该问题将由目标的 ABI 解决——不同的 ABI 不一定以相同的方式解决。

在任何情况下,如果作为公共 API 的一部分意味着这些类型的定义暴露给库用户,并且允许/期望库客户端直接访问成员,那么您必须假设对成员的任何更改一个结构破坏了二进制兼容性。

即使布局相对于原来的成员没有改变,你现在也多了一个老客户不知道的成员。然后,您不能依赖库的用户在分配自己的实例时将该新成员设置为适当的值。如果你(已经)坚持让用户依赖库提供的某种初始化函数,这会有所缓解,但即使你这样做,“我们的更新破坏了你的程序,因为它不正确地使用了我们的库”是一个强行推销,不不管多么真实。

© www.soinside.com 2019 - 2024. All rights reserved.