逐个填充字符缓冲区

时间:2019-05-07 14:09:47

标签: fortran

在Fortran 2008中,我试图以一种高效且易读的方式逐个填充大型字符缓冲区。

对于背景,该代码用于分子动力学代码的输出例程。它应该为包含原子属性的输出文件创建内容。每个属性的确切格式取决于其值。使用MPI-IO在一次调用中对内容进行缓冲和写入,因此不能直接写入文件。可以假定缓冲区足够大。

在C语言中,使用sprintf可以很容易实现,它返回写入的字节数。然后可以将其用于计算下一篇文章应该写在哪里。

在Fortran中,我不知道一种获取write语句写入的字符数的方法。这意味着我必须使用难看而脆弱的代码,例如:

integer :: nchars, len, iatom
character(len=SOMETHING_LARGE) :: strbuf

nchars = 0

! In a loop of iatom = 1, numatoms
! Many similar writes, with different cases for the format
! based on the actual values.
len = 3 * (1 + 11)
write(strbuf(nchars+1 : nchars+len), &
      '(3(1x,f11.7))') x(:, iatom)
nchars = nchars + len

请注意,我必须手动计算写入缓冲区的片段的长度,因为未超过上限意味着(200MB)缓冲区的其余部分将填充空格。这意味着我不能使用自动确定要使用的数字位数的格式。另外,如果在不更改len的情况下更改了格式,代码也会中断。另外,我认为必须将len作为字符串切片的终点来传递。

我通过使用sprintf包装C bind(C)设计了一种解决方法。造成这一点非常难看的是,由于Fortran标准明确将bind(C)中的vararg函数排除在外,因此我必须首先在C中为每种参数类型组合(例如'string,real,real ,int,real','string,string,real,real,real,int',...),然后为Fortran中的每个接口编写一个bind(C)接口。尽管它的脆性稍差(由于某种原因,它快了50%),但它仍然很丑陋,尤其是因为它混合了C和Fortran。

为进行比较,纯C语言中的相同代码:

char *buf = ...;
char *ptr = buf;
...
ptr += sprintf(ptr, "%g %g %g", x[3*i], x[3*i+1], x[3*i+2]);

有没有办法在Fortran中获得类似的清晰度和鲁棒性?

1 个答案:

答案 0 :(得分:0)

您可以让编译器/进程跟踪长度

character(len=37) strtmp
character(len=:), allocatable :: strbuf
strbuf = ''
!
! In your loop...
!
   write(strmp, '(3(1X,F11.7))') x(:,iatom)
   strbuf = trim(strbuf) // strtmp