在类中添加枚举定义是否会破坏其二进制向后兼容性?

时间:2011-11-18 14:41:19

标签: c++ gcc enums binary-compatibility

我知道添加static成员函数很好,但enum定义怎么样?没有新的数据成员,只是它的定义。


一点背景:

我需要添加一个static成员函数(在一个类中),它将通过其字符串表示来识别(函数)IP地址的版本。我想到的第一件事就是为enumIPv4IPv6声明Unknown,并使此enum返回我的函数代码。

但我不想打破二进制向后兼容性。

一个非常糟糕的问题(对于SO) - 这里有任何来源或问题,我可以阅读更多关于此的内容吗?我的意思是 - 什么打破了二进制兼容性和什么 - 没有。或者它取决于很多东西(比如架构,操作系统,编译器......)?


编辑:关于@PeteKirkham的评论:好的,至少 - 有没有办法测试/检查已更改的ABI,或者最好发布有关该问题的新问题?

EDIT2 :我刚发现SO Question : Static analysis tool to detect ABI breaks in C++ 。我认为它在某种程度上与此相关,并回答了关于检查二进制兼容性的工具的部分。这就是我在这里联系它的原因。

2 个答案:

答案 0 :(得分:6)

这里的真正问题显然是为什么使它成为一个类(静态)成员?

从定义中可以明显看出,这可能完全是自己的命名空间(可能是头文件)中的自由函数,或者如果在源文件中的匿名命名空间中使用了隔离的定义。

虽然这仍然可能会破坏ABI,但实际上这需要一个有趣的编译器。

至于ABI破损:

  • 修改类的大小:添加数据成员,除非你设法将它们存入以前未使用的填充(当然是特定于编译器)
  • 修改类的对齐方式:更改数据成员,有人工膨胀对齐(联合)的技巧,但放气需要编译器特定的编译指示或属性和兼容的硬件
  • 修改vtable的布局:添加虚拟方法可能会更改vtable中先前虚拟方法的偏移量。对于gcc,vtable按声明的顺序排列,因此在最后添加虚方法有效...但是它不能在基类中工作,因为vtable布局可以与派生类共享。 最佳被视为冻结
  • 修饰函数的签名:符号的名称通常取决于函数本身的名称及其参数的类型(加上方法的类名和方法的限定符)。您可以在参数上添加顶级const,但无论如何都会被忽略,您通常可以更改返回类型(这可能会带来其他问题)。请注意,添加具有默认值的参数会破坏ABI,就签名而言,将忽略默认值。 最佳被视为冻结
  • 删除先前导出符号的任何函数或类(即具有直接或继承虚拟方法的类)

我可能已经忘记了一两点,但这应该让你已经有一段时间了。

ABI的例子:Itanium ABI

答案 1 :(得分:5)

正式......如果链接的文件是针对两个不同的编译的 你的类的版本,你违反了一个定义规则,哪个 是未定义的行为。实际上...关于唯一突破的事情 二进制兼容性是添加数据成员或虚函数 (非虚函数很好),或更改a的名称或签名 函数或任何涉及基类的东西。而这似乎是 通用 - 我不知道规则所在的编译器 不同。