sizeof(struct)如何帮助提供ABI兼容性?

spi*_*iky 5 c api compatibility abi

假设C库必须与应用程序代码共享结构的细节,并且必须保持API和ABI向后兼容性.它试图通过检查传递给它的结构的大小来做到这一点.

比如说,需要更新以下结构.在库版本1中,

typedef struct {
    int size;
    char* x;
    int y;
} foo;
Run Code Online (Sandbox Code Playgroud)

在库的第2版中,它更新为:

typedef struct {
    int size;
    char* x;
    int y;
    int z;
} foo_2;
Run Code Online (Sandbox Code Playgroud)

现在,库版本2想要检查应用程序是将新的foo_2还是旧的foo作为参数arg传递给函数.它假定应用程序已设置arg.sizesizeof(foo)sizeof(foo_2)尝试确定应用程序代码是否为版本2.

if(arg.size == sizeof(foo_2)) {
    // The application groks version 2 of the library. So, arg.z is valid. 
} else {
    // The application uses of version 1 of the library. arg.z is not valid.
}
Run Code Online (Sandbox Code Playgroud)

我想知道为什么这不会失败.在GCC 4.6.3,与-O3标志,无论是sizeof(foo)sizeof(foo_2)是24,所以,不会V2库中的代码看不懂,如果应用程序传递一个类型的结构foofoo_2?如果是的话,为什么这种方法似乎被使用了?

http://wezfurlong.org/blog/2006/dec/coding-for-coders-api-and-abi-considerations-in-an-evolving-code-base/

http://blogs.msdn.com/b/oldnewthing/archive/2003/12/12/56061.aspx


关注问题:是否有充分的理由支持使用sizeof(struct)版本歧视?正如评论中所指出的,为什么不在version共享结构中使用显式成员?

Ded*_*tor 2

为了符合您的观察,我假设

  • char*大小为 8,对齐方式为 8。
  • int大小为 4,对齐方式为 4。
  • 您的实施使用最佳包装。

你是对的,在这种情况下,你的旧结构和新结构将具有相同的大小,并且由于你的版本鉴别器是结构大小,所以升级是一个破坏 ABI 的更改。(很少有逻辑错误也是语法错误,并且编译器无法诊断前者)。

在该方案下,只有对结构进行更改,导致大小更大,并且新结构包含旧结构的所有字段且偏移量相同,才可以实现 ABI 兼容:添加一些虚拟变量。


不过,有一种可能可以挽救这一局面:

  • 如果字段包含以前无效的值,则可能表明其他任何内容都可能需要解释为差异。

  • 正确的解决方案是填充结构的 v2,使其不具有相同的“sizeof” (2认同)