将成员添加到 C 样式结构并向后兼容
假设我有一个在低级代码深处定义的结构,以最疯狂和未知的方式到处使用:
struct T {
unsigned short name_len;
char d_name[LENGTH];
}
带有附带的函数,用需要放在那里的任何东西填充 d_name ,比如
struct T* fill( somethingOrOther* X)
我想扩展旧的结构+function 包含一个新变量:
struct T {
unsigned short name_len;
char d_name[LENGTH];
unsigned short type_len;
char d_type;
}
新版本的函数还将用有用的东西填充 d_type 变量。
这种类型的更改会破坏 API 吗?难道我不能只使用新 T 代替旧 T,并另外访问新成员吗?
Say I have a struct defined somewhere deep in low-level code used all over the place in the most crazy and unknown ways:
struct T {
unsigned short name_len;
char d_name[LENGTH];
}
With accompanying functions that fill d_name with whatever needs to be put there, like
struct T* fill( somethingOrOther* X)
And I would like to extend the old struct+function to include a new variable:
struct T {
unsigned short name_len;
char d_name[LENGTH];
unsigned short type_len;
char d_type;
}
and the new version of the function would also fill the d_type variable with useful things.
Would this type of change break the API? Couldn't I just use the new T instead of the old T, and additionally access the new members?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
像这样扩展你的结构可能是有意义的:
然后你可以安全地使用 newT 指针作为 T 指针; C 标准保证结构体的第一个元素之前没有填充。
It might make sense to extend your structs like this:
Then you can safely use a newT pointer as a T pointer; the C standard guarantees that there is no padding before the first element of a struct.
只要使用此 API 的代码仅获取
T
对象作为库返回的指针,并且不声明它们本身,malloc
它们本身(使用sizeof( struct T)
),或者做任何其他取决于结构大小的事情,那么应该没问题。如果调用代码访问了结构体的内容,则需要确保将新成员放在结构体的末尾。一个可能的额外考虑因素是,是否有任何代码依赖于位于结构末尾的 d_name,以便在声明的大小不适合时为更大的名称分配空间并存储更大的名称。我之所以提出这个问题,是因为成员的名称表明该结构类似于
dirent
,而这是dirent
的传统做法。As long as the code using this API only obtains
T
objects as pointers returned by the library, and does not declare them itself,malloc
them itself (usingsizeof(struct T)
), or do anything else that depends on the size of the struct, then it should be fine. If the calling code accessed the contents of the struct, you need to make sure you put new members at the end of the struct.One possible additional consideration is whether any code depends on
d_name
being at the end of the structure in order to allocate space for and store larger names if the declared size does not fit. I only bring this up because the names of the members suggest the struct is something likedirent
and that's traditional practice fordirent
.如果 T 真的以疯狂和未知的方式到处使用,那么这样的改变很可能会破坏某些东西。在某个地方,会有一段代码具有 T 的本地声明,而不是使用头文件,或者将“mystruct *”转换为“T *”,或者同样令人反感的东西。
If T really is used all over the place in crazy and unknown ways, then a change like that is likely to break something. Somewhere there will be a piece of code that has a local declaration of T instead of using your header file, or casts a 'mystruct *' to a 'T *', or something equally repugnant.
是的-当您使用这样的不透明指针时,它与内容无关。只要您的用户只使用过不透明指针,您就可以随意修改该结构及其实现。
Yes- when you use an opaque pointer like that, then it is irrelevant of the contents. As long as your users only ever used the opaque pointers, you can muck around with the struct and it's implementation all you like.
疯狂和未知是不好的。最好的办法是扫描代码库中的 struct T 并检查它的使用方式,另一种方法是更改它并查看是否有问题......如果代码仅使用不透明指针,那么您应该是安全的。如果代码访问成员,但没有做一些奇怪的事情,那么通过完整的重新编译,您也应该是安全的。
如果它做了一些奇怪的事情,比如 rettops 的例子,即使 Jukka 的提示也可能无济于事。该代码可以使用 sizeof 的硬编码值在这些结构的数组中进行指针算术......
Crazy and unknown is not good. The best bet is to scan through the codebase for struct T and examine how it is used, with the alternative approach of changing it and see if something breaks... If the code only uses opaque pointers, you should be on the safe side. If the code accesses the members, but doesn't do something weird, you should be safe too, with a complete recompilation.
If it does something weird, like the examples of rettops, even Jukka's tip may not help. The code could use a hardcoded value for the sizeof to do pointer arithmetic within an array of these structs...