我知道C中的结构可能不会像代码中那样布局内存.例如:
struct a {
short x;
int y;
};
Run Code Online (Sandbox Code Playgroud)
假设2字节短路和4字节整数,实际上可能在内存中占用8个字节,因为编译器希望在4字节边界上对齐成员...因此在x和y之间存在2个字节的松弛.
这使得读取和写入结构在语言,编译器和硬件之间不可移植.读取和写入它们的唯一方法是成员.是的,Endianness也是一个问题,交换必须在成员级别进行,但我们假设这不是问题.
Fortran有一个派生类型(结构)的"序列"说明符,它告诉编译器在给定内存时将成员布局在内存中.这允许便携式读取和写入派生类型.
我的问题是:有没有办法在便携式(可维护)方式中用C做类似的事情?
是的,Fortran 2003引入了bind(C)说明符,它告诉编译器与伴随的C编译器完全相同
type, bind(C) :: a
components
end type
Run Code Online (Sandbox Code Playgroud)
此外,该iso_c_binding模块(整个Fortran 2003 C互操作性的子部分)定义了可帮助您连接C和Fortran内部类型的常量:
use intrinsic :: iso_c_binding, only: c_short, c_int
type, bind(C) :: a
integer(c_short) :: x
integer(c_int) :: y
end type
Run Code Online (Sandbox Code Playgroud)
据说这种类型可与您的C结构互操作.
C互操作性在编译器中得到了广泛的支持.很难找到不支持此功能但仍受其供应商支持的编译器.
sequence混合C和Fortran时要远离.根据标准,序列类型不能互操作.
小智 2
据我所知,没有 100% 干净的解决方案。我通常做的是创建两个名为pack_on.h和 的头文件pack_off.h。要定义不带填充的结构:
#include <pack_on.h>
struct a {
short x;
int y;
} PACKED_STRUCTURE;
#include <pack_off.h>
Run Code Online (Sandbox Code Playgroud)
头文件包含编译指示或满足编译器所需的任何内容,例如:
#ifdef _MSC_VER
#pragma pack(1)
#define PACKED_STRUCTURE /* nothing */
#endif
#ifdef __GNUC__
#define PACKED_STRUCTURE __attribute__(packed)
#endif
Run Code Online (Sandbox Code Playgroud)
正如您已经说过的,当二进制布局成为问题时,字节顺序通常也很重要。上述解决方案中没有解决这个问题。
请注意,在整个代码中使用打包结构也是一个坏主意。当您不强制使用这些打包结构时,编译器添加的填充对于快速内存访问非常有用。
在许多应用程序中,最好仅在应用程序的一层中使用这些打包结构,该层处理读取和写入这些打包结构,并将它们复制到正确对齐的结构中,然后将它们传递到应用程序的核心以进行进一步处理。