在C中读写结构

Mcf*_*fly 8 c fortran

我知道C中的结构可能不会像代码中那样布局内存.例如:

struct a {
     short x;
     int y;
};
Run Code Online (Sandbox Code Playgroud)

假设2字节短路和4字节整数,实际上可能在内存中占用8个字节,因为编译器希望在4字节边界上对齐成员...因此在x和y之间存在2个字节的松弛.

这使得读取和写入结构在语言,编译器和硬件之间不可移植.读取和写入它们的唯一方法是成员.是的,Endianness也是一个问题,交换必须在成员级别进行,但我们假设这不是问题.

Fortran有一个派生类型(结构)的"序列"说明符,它告诉编译器在给定内存时将成员布局在内存中.这允许便携式读取和写入派生类型.

我的问题是:有没有办法在便携式(可维护)方式中用C做类似的事情?

Vla*_*r F 5

是的,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)

正如您已经说过的,当二进制布局成为问题时,字节顺序通常也很重要。上述解决方案中没有解决这个问题。

请注意,在整个代码中使用打包结构也是一个坏主意。当您不强制使用这些打包结构时,编译器添加的填充对于快速内存访问非常有用。

在许多应用程序中,最好仅在应用程序的一层中使用这些打包结构,该层处理读取和写入这些打包结构,并将它们复制到正确对齐的结构中,然后将它们传递到应用程序的核心以进行进一步处理。