使用COMMON语句编译包含Fortran库的C ++

时间:2012-06-13 13:48:30

标签: c++ fortran libraries fortran-common-block

我正在编译一个需要一些库的C ++程序。这些库的代码是用Fortran编写的,包含COMMON块。基本上我做的事情是:

g++ -o main.cpp main lib1.a lib2.a

Lib1.a和lib2.a在Fortran中编码:

gfortran -c -o lib1.a Code1.F
gfortran -c -o lib2.a Code2.F

两者都包含一个包含以下内容的头文件:

double precision var1,var2
double precision var3,var4

common /block1/ var1,var2
common /block2/ var3,var4

似乎COMMON块出了问题。例如,在公共变量或添加新变量之后更改变量的顺序会导致随机不一致的结果。

我知道COMMON语句不应该在可能的情况下使用,但我不知道在这种情况下会出现什么问题。

3 个答案:

答案 0 :(得分:1)

根据您的编译器Fortran,它可能在变量之间插入填充。也许Fortran和C ++编译器对此不以为然。只是一个猜测。

如果您愿意更改Fortran代码,那将有助于使用ISO C Binding,因为它指示Fortran编译器生成符合C编译器约定的代码。 http://software.intel.com/sites/products/documentation/hpc/compilerpro/en-us/fortran/lin/compiler_f/bldaps_for/common/bldaps_interopc.htm处有一个共同的块示例。基于这个例子:

use, intrinsic :: iso_c_binding
real (c_double) :: var1, var2, var3, var4
common /block1/ var1, var2
common /block2/ var3, var4
bind (C) :: /block1/, /block2/

如果您愿意进行更多的mod,更好的选择是模块变量。然后就不用担心内存中的布局了。

module global_vars
use, intrinsic :: iso_c_binding
real (c_double), bind (C) :: var1, var2, var3, var4
end module global_vars

答案 1 :(得分:1)

COMMON中的变量顺序很重要,并且在更改订单后会发生不良事件。它应该与使用公共块的每个地方相同,包括在C ++程序中。什么是微不足道的是给这些变量的名称。例如。在一个子程序中你可以:

double precision a, b
common /block1/ a, b

在另一个子程序中你可以:

double precision c, d
common /block1/ c, d

仍然ac将共享相同的内存位置。这同样适用于bd。这可能会导致混淆,通常的做法是将变量和公共块声明放在include - d的文件中,每个子例程使用特定的公共块,就像你的情况一样。现在,如果您在任何常见块中更改某些内容,则所有子例程都会看到它已更改,一切都将按预期工作。

问题是您还必须更改相应的C结构,以使其与更改的公共块对应。 E.g。

double precision a, b
common /block1/ a, b

在C中对应:

struct common_block1
{
    double a;
    double b;
};
extern struct common_block1 block1_;

(注意:不支持bind(C)属性的旧版Fortran编译器会在每个导出的标识符的末尾添加下划线,因此在C / C ++中,您必须将block1引用为block1_ })

如果将公共块更改为:

integer a
double precision b, c
common /block1/ a, b, c

您还应该将C结构更改为:

struct common_block1
{
   int a;
   double b;
   double c;
};

所有给出C和Fortran编译器的都使用相同的内存对齐规则。通常可以使用编译器选项(C / C ++ / Fortran)和类型属性(C / C ++)来控制对齐。使用ISO_C_BINDING Fortran模块可以保证在Fortran和C中使用具有相同存储大小的类型。建议您首先放置最大的对象(例如数组,(DOUBLE) COMPLEX变量,DOUBLE PRECISION变量等等,在公共区块的开头,然后是较小的对象,等等。

答案 2 :(得分:0)

我想我理解了这个bug的起源。我首先编译了库lib1.a,包括头文件。然后我实际修改了这个头文件(特别是公共块)并编译了库lib2.a.这似乎是合乎逻辑的,这导致了不同库中两个公共块之间的错误...

我会详细检查这个,但我很确定这是解释。感谢您的建议,它帮助我检查了所有内容,这就是我找到解决方案的方式!