【问题标题】:Adding members to a C-style struct and backwards compatibility将成员添加到 C 样式结构和向后兼容性
【发布时间】:2010-07-22 13:57:20
【问题描述】:

假设我在低级代码深处定义了一个结构,该结构以最疯狂和未知的方式在各处使用:

struct T {
    unsigned short name_len;
    char d_name[LENGTH];
}

附带的函数会在 d_name 中填充需要放入的任何内容,例如

struct T* fill( somethingOrOther* X)

我想扩展旧的 struct+function 以包含一个新变量:

struct T {
    unsigned short name_len;
    char d_name[LENGTH];
    unsigned short type_len;
    char d_type;
}

并且新版本的函数也会用有用的东西填充 d_type 变量。

这种类型的更改会破坏 API 吗?我不能只使用新的 T 代替旧的 T,并额外访问新成员吗?

【问题讨论】:

  • 我猜关键问题是:是否保证offsetof(struct T, d_name) 的值在T 的旧定义和新定义中是相同的?

标签: c api struct backwards-compatibility


【解决方案1】:

只要使用此 API 的代码仅获取 T 对象作为库返回的指针,并且不声明它们本身,malloc 它们本身(使用 sizeof(struct T)),或做任何其他依赖于结构的大小,那么它应该没问题。如果调用代码访问了结构的内容,则需要确保将新成员放在结构的末尾。

一个可能的额外考虑是任何代码是否依赖d_name 位于结构的末尾,以便在声明的大小不适合的情况下为更大的名称分配空间和存储。我之所以提出这一点,是因为成员的名称表明该结构类似于dirent,而这是dirent 的传统做法。

【讨论】:

  • 该死,我在等人来解决这个问题:)。我找到了一个为 mingw 实现 d_type 的补丁,但他们也使用了一个包含旧结构的包装器结构。我向 mingw-w64 开发人员提出了建议,但到目前为止还没有收到回复。感谢您提供信息丰富的答案。
  • 那么在这种情况下,我认为有一些事情需要考虑。从 API 的角度来看,将新成员放在 d_name 之前会更好,因为它允许将来将 d_name 视为可变长度。另一方面,从 ABI 的角度来看,必须在最后添加新成员。我怀疑很大程度上取决于 ABI(afaik 此代码是静态链接的),但可能存在使用 dirent 并与调用程序返回 dirent 对象的 DLL,在这种情况下存在 ABI 问题,所以保留 ABI 可能是值得的。
  • 顺便说一句,既然你提到你正在修补 mingw,你能在这里看看我的问题吗:stackoverflow.com/questions/3228828/… 我一直在为一个我正在努力改进的项目进行 UTF-8 修补支持Windows,但我自己不做Windows。您是否有兴趣尝试集成和测试我编写的代码?
【解决方案2】:

像这样扩展你的结构可能是有意义的:

struct newT {
    struct T t;
    int newElement;
    ...
}

那么你就可以放心地使用 newT 指针作为 T 指针了; C 标准保证结构的第一个元素之前没有填充。

【讨论】:

    【解决方案3】:

    如果 T 真的以疯狂和未知的方式到处使用,那么这样的更改可能会破坏某些东西。某处将有一段代码具有 T 的本地声明,而不是使用您的头文件,或者将 'mystruct *' 强制转换为 'T *',或者同样令人反感的东西。

    【讨论】:

      【解决方案4】:

      是的-当您使用这样的不透明指针时,它与内容无关。只要您的用户只使用过不透明的指针,您就可以随意使用结构及其实现。

      【讨论】:

      • 所以,是的,它不会破坏 API? (有点混淆了我的两个问题;))
      • 只要重新编译所有使用指针以外的任何东西的代码,就可以了。
      【解决方案5】:

      疯狂和未知不好。最好的办法是扫描 struct T 的代码库并检查它的使用方式,另一种方法是更改​​它,看看是否有问题......如果代码只使用不透明的指针,你应该是安全的。如果代码访问成员,但没有做一些奇怪的事情,你也应该是安全的,完全重新编译。

      如果它做了一些奇怪的事情,比如 rettops 的例子,即使是 Jukka 的提示也可能无济于事。代码可以使用 sizeof 的硬编码值在这些结构的数组中进行指针运算...

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2019-04-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-10-10
        相关资源
        最近更新 更多