2

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

4

3 回答 3

1

COMMON块中变量的顺序重要,更改顺序后会发生坏事。在使用公共块的任何地方都应该是相同的,包括在 C++ 程序中。无关紧要的是这些变量的名称。例如,在一个子程序中,您可以:

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

在另一个子程序中,您可以:

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

仍然a并且c将共享相同的内存位置。这同样适用于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++ 中,您必须引用block1as 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_BINDINGFortran 模块可以保证在 Fortran 和 C 中使用相同存储大小的类型种类。建议您首先将最大的对象(例如数组、(DOUBLE) COMPLEX变量、DOUBLE PRECISION变量等)放在公共块的开头,然后是较小的对象等等。

于 2012-06-13T14:21:26.983 回答
1

根据您的编译器的 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
于 2012-06-13T14:02:25.647 回答
0

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

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

于 2012-06-24T16:02:52.413 回答