【问题标题】:Reading and writing structures in CC中的读写结构
【发布时间】:2014-11-30 23:23:07
【问题描述】:

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

struct a {
     short x;
     int y;
};

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

这使得读写结构无法跨语言、编译器和硬件移植。读取和写入它们的唯一方法是逐个成员。是的,字节序也是一个问题,交换必须在成员级别完成,但我们假设这不是问题。

Fortran 有一个派生类型(结构)的“序列”说明符,它告诉编译器按照给定的成员在内存中布局。这允许可移植地读取和写入派生类型。

我的问题是:有没有办法在 C 中以可移植(且可维护)的方式做类似的事情?

【问题讨论】:

  • 大多数编译器都有对 pack 结构的指令,因此它可以在成员之间有其他(或没有)填充。快速搜索应该可以帮助您找到编译器所需的内容。然而,字节序问题并不是那么容易克服,但如果你只针对单个硬件平台,你应该没问题。
  • 序列化和反序列化为文本,避免字节序、打包和可移植性方面的任何问题。
  • Fortran 的序列类型概念从根本上不允许“可移植地读取和写入派生类型”。跨不同的编译器和不同的平台(以及同一平台上的不同编译器选项)您仍然可能存在兼容性问题。

标签: c fortran


【解决方案1】:

是的,Fortran 2003 引入了 bind(C) 说明符,它告诉编译器执行与配套 C 编译器完全相同的操作

type, bind(C) :: a
  components
end type

此外,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

据说这种类型可以与您的 C 结构互操作

C 互操作性在编译器中得到非常广泛的支持。很难找到不支持此功能但仍受其供应商支持的编译器。

在混合 C 和 Fortran 时远离sequence。序列类型不能按照标准进行互操作。

【讨论】:

    【解决方案2】:

    据我所知,没有 100% 干净的解决方案。我通常做的是创建两个名为pack_on.hpack_off.h 的头文件。定义没有填充的结构:

    #include <pack_on.h>
    
    struct a {
        short x;
        int y;
    } PACKED_STRUCTURE;
    
    #include <pack_off.h>
    

    头文件包含编译指示或满足编译器所需的任何内容,例如:

    #ifdef _MSC_VER
    #pragma pack(1)
    #define PACKED_STRUCTURE /* nothing */
    #endif
    
    #ifdef __GNUC__
    #define PACKED_STRUCTURE __attribute__(packed)
    #endif
    

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

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

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

    【讨论】:

    • 在解包过程中你还可以进行字节交换来处理字节序
    猜你喜欢
    • 1970-01-01
    • 2011-08-30
    • 2014-03-10
    • 1970-01-01
    • 2023-03-17
    • 2014-04-24
    • 2016-06-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多