在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中获得类似的清晰度和鲁棒性?
答案 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