库头文件中的结构定义和编译差异
我有一个代码被编译成一个库(dll、静态库等)。我希望这个库的用户使用一些结构来传递一些数据作为库函数的参数。我考虑过在 API 头文件中声明该结构体。
- 考虑到使用不同的编译器进行编译,相对于结构对齐或其他我没有考虑到的事情,这样做是否安全?
- 库及其用户是否需要使用相同的编译器(和标志)?
几点说明:
- 我考虑过给用户一个指针并通过库中的函数设置所有结构,但这将使 API 使用起来并不舒服。
- 这个问题是关于C的,尽管很高兴知道c++中是否存在差异。
I have a code which is compiled into a library (dll, static library and so). I want the user of this library to use some struct to pass some data as parameters for the library function. I thought about declaring the struct in the API header file.
- Is it safe to do so, considering compilation with different compilers, with respect to structure alignment or other things I didn't think about?
- Will it require the usage of the same compiler (and flags) for both the library and its user?
Few notes:
- I considered giving the user a pointer and set all the struct via functions in the library, but this will make the API really not comfortable to use.
- This question is about C, although it would be nice to know if there's a difference in c++.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
如果它是常规/静态库,则应使用相同的编译器来编译库和应用程序。我能想到的有几个原因:
但是,您可能经常使用同一编译器的略有不同版本来编译库和使用它的应用程序。通常情况下,没问题。但有时某些更改会破坏代码。
您可以在该头文件中实现一些“初始化”函数(声明为静态内联),以确保类型、类型大小、对齐和打包与编译库的预期相同。使用此库的应用程序必须在使用库的任何其他部分之前调用此函数。如果情况与预期不一样,则该函数一定会失败并导致程序终止,可能还会有一些对失败的良好文字描述。这并不能完全解决编译器有些不兼容的问题,但它可以防止无声的和神秘的故障。有些事情可以使用预处理器的
#if
和#ifdef
指令进行检查,并导致#error
编译错误。此外,可以通过在结构声明中插入显式填充字节并强制紧密打包(例如,通过使用许多编译器都支持的#pragma pack)来缓解结构打包问题。这样,如果字体大小相同,则默认包装是什么并不重要。
您也可以将相同的方法应用于 DLL,但您确实应该期望调用应用程序是使用不同的编译器编译的,而不是依赖于相同的编译器。
If it's a regular/static library, the library and application should be compiled using the same compiler. There're a few reasons for this that I can think of:
You may, however, often use slightly different versions of the same compiler to compile the library and the application using it. Usually, it's OK. Sometimes there're changes that break the code, though.
You may implement some "initialization" function in that header file (declared as
static inline
) that would ensure that types, type sizes, alignment and packing are the same as expected by the compiled library. The application using this library would have to call this function prior to using any other part of the library. If things aren't the same as expected, the function must fail and cause program termination, possibly with some good textual description of the failure. This won't solve completely the problem of having somewhat incompatible compilers, but it can prevent silent and mysterious malfunctions. Some things can be checked with the preprocessor's#if
and#ifdef
directives and cause compilation errors with#error
.In addition, structure packing problems can be relieved by inserting explicit padding bytes into structure declarations and forcing tight packing (by e.g. using
#pragma pack
, which is supported by many compilers). That way if type sizes are the same, it won't matter what the default packing is.You can apply the same to DLLs as well, but you should really expect that the calling application has been compiled with a different compiler and not depend on the compilers being the same.
所有 Windows API 都会疯狂地抛出结构,因此显然这是每天都会做的事情并且它有效。当然,这并不意味着您的担忧没有根据:)
我建议使您的结构体字段具有显式宽度类型(int32_t 等),并且可能明确指定打包方式会在除您之外的任何编译器上中断,即
All Windows APIs throw structs around like crazy so obviously this is something that is done every day and it works. Of course it doesn't mean that your concerns are not valid :)
I would suggest making your structure's fields have explicit width types (int32_t etc) and maybe specify explicitly that that the packing in a way which would break on any compiler but yours, i.e.