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++ プログラムを含め、共通ブロックが使用されているすべての場所で同じである必要があります。重要でないのは、それらの変数に付けられた名前です。たとえば、1 つのサブルーチンで次のようにすることができます。

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

そして別のサブルーチンでは、次のようにすることができます:

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

それでもac同じメモリ位置を共有します。bとについても同様ですd。これは混乱を招く可能性があり、通常は、変数と共通ブロックの両方の宣言をinclude、特定の共通ブロックを使用するすべてのサブルーチンによって -d されるファイルに入れることです。共通ブロックのいずれかで何かを変更すると、すべてのサブルーチンが変更されたことを認識し、すべてが期待どおりに機能します。

問題は、変更された共通ブロックに対応させるために、対応する C 構造体も変更する必要があることです。例えば

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

C では次のように対応します。

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

(注: 属性をサポートしない古い Fortran コンパイラではbind(C)、エクスポートされた各識別子の末尾にアンダースコアが付けられるため、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++) で制御できます。Fortran モジュールを使用ISO_C_BINDINGすると、Fortran と C で同じストレージ サイズの型の種類が使用されることが保証されます。最初に最大のオブジェクト (配列、(DOUBLE) COMPLEX変数、DOUBLE PRECISION変数など) を共通ブロックの先頭に配置し、次に小さいオブジェクトを配置することをお勧めします。オブジェクトなど。

于 2012-06-13T14:21:26.983 に答える
1

Fortran コンパイラによっては、変数間にパディングが挿入される場合があります。おそらく、Fortran と C++ のコンパイラはこれに同意していません。推測です。

Fortran コードを変更する場合は、ISO C Binding を使用すると便利です。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
于 2012-06-13T14:02:25.647 に答える
0

バグの原因がわかったと思います。最初に、ヘッダー ファイルを含むライブラリ lib1.a をコンパイルしました。次に、実際にこのヘッダー ファイル (特に共通ブロック) を変更し、ライブラリ lib2.a をコンパイルしました。これにより、異なるライブラリ内の 2 つの共通ブロック間でミスマッチが発生することは論理的に思えます...

これを詳細に確認しますが、これが説明であると確信しています。あなたのアドバイスをありがとう、それは私がすべてをチェックするのを助けました、そしてこれが私が解決策を見つけた方法です!

于 2012-06-24T16:02:52.413 に答える