编译C++包括带有 COMMON 语句的 Fortran 库

Compiling C++ including Fortran libraries with COMMON statements

本文关键字:Fortran 语句 COMMON C++ 包括带 编译      更新时间:2023-10-16

我正在编译一个需要一些库的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 语句,但我看不出在这种情况下可能有什么问题。

根据编译器的

Fortran,它可能在变量之间插入填充。 也许Fortran和C++编译器对此存在分歧。 只是一个猜测。

如果您愿意更改 Fortran 代码,使用 ISO C 绑定会有所帮助,因为这会指示 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/

如果您愿意制作进一步的模组,更好的选择是模块变量。 然后就不用担心内存中的布局。

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

变量在COMMON块中的顺序很重要,更改顺序后会发生不好的事情。在使用公共块的任何地方,包括在C++程序中,都应该是相同的。微不足道的是给这些变量命名。例如,在一个子程序中,您可以拥有:

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

在另一个子例程中,您可以拥有:

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

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

问题是你还必须改变相应的C结构,以便使其与改变的公共块对应。

例如
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变量等)放在公共块的开头,然后是较小的对象等。

我想

我明白了这个错误的起源。我首先编译了库lib1.a,包括头文件。然后我实际上修改了这个头文件(尤其是公共块)并编译了库lib2.a。这似乎合乎逻辑,在不同库中的两个公共块之间引起混乱......

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