【问题标题】:Fortran serialization using C_LOC and C_F_POINTER使用 C_LOC 和 C_F_POINTER 的 Fortran 序列化
【发布时间】:2015-05-07 05:38:24
【问题描述】:

我正在寻找 Fortran 库或在 Fortran 中将数据序列化到内存缓冲区的首选方法。

研究该主题后,我找到了使用 EQUIVALENCE 语句和 TRANSFER 内在函数的示例。我编写了代码来测试它们,它们都有效。在我有限的测试中,传递函数似乎比等价语句慢很多。但是,我发现一些参考资料表明一般不使用等价声明。

所以,我一直在尝试想出另一种有效序列化数据的方法。在准备好 Fortran 2003 规范后,我发现我可以一起使用 C_LOC 和 C_F_POINTER 将我的“字节”数组转换为所需的数据类型(int、real 等)。初步测试表明它正在工作并且比传递函数更快。下面列出了一个示例程序。我想知道这是否是对 C_LOC 和 C_F_POINTER 函数的有效使用。

谢谢!

  program main
    use iso_c_binding
    implicit none


    real(c_float)             :: a, b, c
    integer(c_int8_t), target :: buf(12)

    a = 12345.6789_c_float
    b = 4567.89123_c_float
    c = 9079.66788_c_float

    call pack_float( a, c_loc(buf(1)) )
    call pack_float( b, c_loc(buf(5)) )
    call pack_float( c, c_loc(buf(9)) )

    print '(A,12I5)', 'Bin: ', buf


  contains


    subroutine pack_float( src, dest )
      implicit none
      real(c_float), intent(in) :: src
      type(c_ptr), intent(in)   :: dest
      real(c_float), pointer    :: p
      call c_f_pointer(dest, p)
      p = src
    end subroutine


  end program

输出:

Bin:   -73  -26   64   70   33  -65 -114   69  -84  -34   13   70

我还在 Python 中对此进行了编码,以仔细检查上面的答案。下面列出了代码和输出。

import struct

a = struct.pack( '3f', 12345.6789, 4567.89123, 9079.66788)
b = struct.unpack('12b', a)
print b

输出:

(-73, -26, 64, 70, 33, -65, -114, 69, -84, -34, 13, 70)

【问题讨论】:

  • 你真正想做什么?我可能很模糊,但对我来说,“序列化”建议采用复杂的数据结构,可能包括一个图形或树状结构的组件,并将其转换为一系列元素(可能是字节)以进行存储或传输。 3 Fortran 实数几乎不需要序列化。
  • 我在您的帖子中找不到任何问题。顺便说一句,如果派生类型不包含指针或可分配对象,则可以直接将其写入输出。
  • @HighPerformanceMark 首先,感谢您抽出宝贵时间发表评论。我想做什么?在具有实时操作约束的应用程序中尽可能高效地记录数据。文件 i/o 成本太高。数据当前存储在内存缓冲区中,并在运行完成后刷新到文件中。当前进程只允许存储标量 32 位整数和实数变量。我上面的代码示例非常简单。尝试确定是否可以这样使用 c_loc 和 c_f_pointer(我以后使用这种方法会遇到障碍吗?)。
  • @VladimirF 感谢您抽出宝贵时间发表评论;我从你的其他帖子/cmets 中学到了很多东西。我的预期问题是——使用 c_loc 和 c_f_pointer 指向缓冲区并“转换”它来存储不同的 fortran 类型(1|2|4|8 字节整数和浮点数、固定数组等)是否有效。我混合了派生类型;许多是固定的,但有些具有动态字段。
  • @HighPerformanceMark 好的;我无法从我最初的研究中找到任何方法。它“确实”对我来说也很奇怪!我进入编程领域的时间不长,但似乎所有的序列化库都使用其他编程语言。实际上,我使用 Fortran 中的 XDR 和 Protobuf 协议为几个派生类型编写了一些测试代码来输出数据。 XDR 似乎更适合我的用例。我只是不想强迫一切都使用大端。考虑过使用 XDR 规范,但将其设为小端。

标签: serialization fortran fortran2003


【解决方案1】:

实际上,以这种方式使用 C_LOC 和 C_F_POINTER 可能会起作用,但形式上它不符合标准。传递给 C_F_POINTER 的 Fortran 指针的类型和类型参数必须与 C 地址指定的对象互操作,或者与最初传递给 C_LOC 的对象的类型和类型参数相同(参见 FPTR 的描述F2008 15.2.3.3 中的参数)。根据您尝试序列化的内容,您可能还会发现对 C_LOC 参数的正式限制(在后来的标准中比 F2003 的限制逐渐减少)开始发挥作用。

(C 等效项需要使用 unsigned char 来实现这种技巧 - 这不一定与 int8_t 相同。)

EQUIVALENCE 集中的项目存在限制,导致该方法不普遍适用(请参阅 F2008 中的限制 C591 到 C594)。通过等价解释对象的内部表示也正式受制于有关变量定义和取消定义的规则 - 尤其参见 F2008 16.6.6 第 1 项。

在 Fortran 中将一个对象表示为不同类型的一致方法是通过 TRANSFER。请注意,使用可分配或指针组件对派生类型的内部表示进行序列化(这就是动态字段的意思吗?)可能没有用。

视情况而定,将实时结果简单地存储在要存储的事物类型的数组中可能更简单、更健壮。

【讨论】:

  • 这是我需要知道的!您的规范参考非常有帮助。使用它们,我能够找到一些英特尔 Fortran 论坛帖子,这些帖子有助于我理解和使用 Transfer 和 Equivalence。我会回去重新考虑我的设计/选项;并在必要时使用 Transfer。谢谢!
猜你喜欢
  • 2020-08-29
  • 2018-10-26
  • 2017-11-10
  • 2020-04-21
  • 2017-11-10
  • 2018-01-02
  • 1970-01-01
  • 2021-12-30
  • 2012-09-05
相关资源
最近更新 更多