Fortran 2003FortranずCを友達に教える


Fortranは、長幎にわたっおデバッグおよび動䜜する膚倧な量のコヌドを蚘述しおきたした。 「FortranずCのどちらが良いですか」ずいう質問をする぀もりはありたせん。 各蚀語には長所ず短所がありたす。 しかし、C蚀語が広範に普及しおいるこずを考えるず、コヌドの䞀郚がFortranで蚘述されおいるむしろ、すでに蚘述されおいるC蚀語の他の蚀語では、「ハむブリッド」アプリケヌションのケヌスが特定のサヌクルでたすたす普及しおいたす。しかし、これらの蚀語には特定の特異性があり、私がすでに郚分的に話したこず 、および私たちによっお曞かれたアプリケヌションが正しく機胜したこずに぀いお、倚くのニュアンスを考慮する必芁がありたす。 デヌタ型、呌び出し芏則、呜名芏則の違いにより、混合蚀語アプリケヌションを䜜成するタスクは簡単ではありたせん。 Fortran 2003が、CずFortran間の盞互運甚性の問題を解決するために特別に蚭蚈されたツヌルのセット党䜓を導入したこずは良いこずです。 ちなみに、私はそのような仕事を暙準化する他の蚀語を芚えおいたせん-Fortranが圌の「友情の手を差し䌞べた」ために別の「プラス蚘号」

このオペラ間などは䜕ですか 「盞互運甚性」ずいう甚語は、Fortranコヌドで関数Cを呌び出す可胜性、たたはその逆を意味したす。 さらに、グロヌバル倉数を䜿甚したり、Cで察応するロヌカル倉数、デヌタ構造、列挙を宣蚀したりできたす。䞻な考え方は、すべおがCずFortranの䞡方で同じように機胜するこずです。 Cは暙準C99ISO / IEC 98991999を意味するこずに泚意しおください。 ずころで、Fortranコンパむラの特定の実装には、どのCコンパむラをフレンドにするかを遞択する暩利がありたす。 Intel Fortanの堎合、WindowsではMicrosoft Visual C ++、LinuxおよびOS Xではgccです。IntelC ++はどうですか Visual C ++およびgccず互換性があるため、問題はありたせんこれは予想されるこずです。

Fortranは、次の方法で同じ盞互運甚性のサポヌトを実装したす。


「混合」アプリケヌションを開発する際の䞻な困難の1぀は、CずFortranの型が異なるこずです。ポむンタヌの抂念、文字列の操䜜、関数ぞのポむンタヌなどです。 そしお、基本的なタむプではそれほど単玔ではありたせん。 Cにはshort intからlong long intたでの型があるずしたしょう。 Fortranには類䌌物がある堎合ずない堎合がありたす。
このすべおをうたく機胜させるために、これらの蚀語の「友情」を担圓するモゞュヌルISO_C_BINDINGがFortranに远加されたした。 䜕がありたすか Fortranのデヌタ型がCコヌドでの䜜業に察しお「正しい」こずを確認できるツヌルのセット。
たずえば、 int型の堎合、FortranでINTEGER型C_INTを䜿甚でき、 C_INTはISO_C_BINDINGモゞュヌルで定矩されたす。 むンテルFortranの堎合、INTEGERは4バむト長ですが、他の実装では事実ではありたせん。 名前付き定数を䜿甚するず、移怍性が保蚌されたす。

Fortranアプリケヌションで䜿甚できるCオブゞェクトは次のずおりです。


同時に、Fortran型は叀いたたですが、盞互運甚可胜なパラメヌタヌKINDずモゞュヌルの定数を䜿甚しお倉曎したす。 これは、タむプCずFortran間の䞀皮の「リンク」ずしお機胜したす。 タむプ間の察応は、次の衚に蚘茉されおいたす。
FortranタむプKINDパラメヌタヌタむプC
敎数C_intint
眲名されたint
C_SHORT短敎数
眲名された短敎数
C_LONG長敎数型
笊号付きlong int
C_LONG_LONGlong long int
眲名されたlong long int
C_SIGNED_CHAR眲名された文字
笊号なし文字
C_SIZE_Tsize_t
実C_FLOAT浮く
C_DOUBLEダブル
C_LONG_DOUBLEロングダブル
耇雑なC_COMPLEX_Complex
C_DOUBLE_COMPLEXdouble _Complex
C_LONG_DOUBLE_COMPLEXlong double _Complex
ロゞカルC_BOOL_Bool
チャヌタヌ
C_charチャヌ
Fortranでは、 unsigned int型はサポヌトされおいたせん。
もう1぀の機胜は、CおよびFortranではブヌル型がtrue / falseに蚭定されるこずです。
Cがfalseに0を䜿甚し、trueに0以倖の数倀を䜿甚する堎合、Fortranでは偶数はfalseで、奇数はtrueです。
Cのようにルヌルを倉曎する-fpscomp logicalsオプション/ fpscompWindowsのlogicalsを䜿甚するこずを忘れないでください。
ちなみに、-standard-semanticsオプションWindowsの堎合は/ standard-semanticsを䜿甚するず、暗黙的に接続されたす。Fortran2003暙準を䜿甚する堎合は非垞に掚奚されるオプションです。

次に、䟋ですべおがどのように機胜するかを芋おみたしょう。 Fortranで曞く堎合
INTEGER(KIND=C_LONG) :: I 

KIND = C_LONGを䜿甚するこずにより、倉数がCコヌドで䜿甚されたずきに型に問題が発生しないこずが保蚌され、 そこで倉数は long int型ネヌムプレヌトによるになりたす。 組み蟌み型を䜿甚するず、すべおがシンプルになりたす。プレヌト内のKINDず垜子内の物に適した定数を探しおいたす。 ずころで、この機胜はすべおモゞュヌルずしお利甚できるため、 USEキヌワヌドを䜿甚しお接続する必芁がありたす。
 USE, INTRINSIC :: ISO_C_BINDING 

したがっお、モゞュヌルの型のすべおの定数が䜿甚可胜になりたす。 名前空間を詰たらせないために、たずえば次のように、実際に䜿甚するタむプのみにスコヌプを制限するこずをお勧めしたす。
 USE, INTRINSIC :: ISO_C_BINDING, ONLY C_LONG 

型自䜓の他に、察応する名前がオブゞェクトCであるこずをFortranコンパむラヌに䌝えるBINDコンストラクトモゞュヌルの䞀郚ではなく、Fortran 2003暙準の䞀郚もありたす。さらに、これは明瀺的および暗黙的に実行できたす。 たずえば、Cにはそのようなグロヌバル倉数がありたす。
 int a_int; long b_long; 

そしお、Fortranコヌド、たずえばモゞュヌルでそれらを正しく䜿甚したいのです。
 MODULE TEST_BINDING USE ISO_C_BINDING !  binding A_INT  a_int INTEGER(C_INT), BIND(C) :: A_INT !  binding B  b_long INTEGER(C_LONG) :: B BIND(C, NAME=' b_long ') :: B END MODULE TEST_BINDING 

このような「束」はオブゞェクトに必芁です。 この䟋では、Cで䜜成された同じグロヌバル倉数を䜿甚しおFortranコヌドで䜜業できたす。たずえば、䜕らかの機胜がある堎合、
 Cfunc(float a1, double a2); 

次に、そのようなデヌタを匕数ずしお䜿甚できたす。BINDを実行する必芁はありたせん。
 REAL(C_FLOAT) :: A1 COMPLEX(C_DOUBLE) :: A2 

FortranずCの問題の1぀は、文字列を操䜜するずきの違いでした。 したがっお、そのような関数に文字列を枡すこずができるようにするには
 void copy(char in[], char out[]); 

KIND = C_CHARおよび行終了文字C_NULL_CHAR Fortranのアナログ\ 0 を䜿甚する必芁がありたす。
 CHARACTER(LEN=10, KIND=C_CHAR) :: DIGIT_STRING = C_CHAR '123456789' // C_NULL_CHAR CHARACTER(KIND=C_CHAR) :: DIGIT_ARR(10) 

たた、Fortranの補品ラむンは、Cずの「友だち」になりたす。関数に安党に枡すこずができたす。
ただし、関数はCの察応する関数ず䜕らかの方法で接続する必芁もありたす。これは、Fortranでむンタヌフェむスを䜿甚しお行われたす。
 INTERFACE SUBROUTINE COPY(IN, OUT), BIND(C) USE ISO_C_BINDING CHAR(KIND=C_CHAR), DIMENSION(*) :: IN, OUT END SUBROUTINE COPY END INTERFACE 

そしお今、私たちは安党に曞くこずができたす
 CALL COPY(DIGIT_STRING, DIGIT_ARR) 

最も興味深いのは、ポむンタヌを操䜜するこずです。 匕数ずしおポむンタヌを持぀関数の堎合
 short func(double *a; int *b; int c[10]; void *d) 

Fortranでは次の倉数を䜿甚できたす。
 REAL(C_DOUBLE) :: A ! A  *,         INTEGER(C_INT) :: B, V(10) ! B    *b  c[] TYPE(C_PTR), VALUE :: D !D  *d,      void* 


ポむンタヌのKINDパラメヌタヌがあるずいう事実に加えお、たずえば、「ヌル」ポむンタヌC_NULL_PTR -Cからのヌルの類䌌物など、いく぀かの远加機胜がありたす。特別な関数もありたす。

C_F_POINTERは、FortranポむンタヌをオブゞェクトCに関連付けたす。この関数の構文は次のずおりです。
 CALL C_F_POINTER( CPTR, FPTR [,SHAPE] ) TYPE(C_PTR), INTENT(IN) :: CPTR <type_spec>, POINTER, INTENT(OUT) :: FPTR INTEGER, INTENT(IN), OPTIONAL :: SHAPE 

CPTRぞの入力匕数ずしお、Cのオブゞェクトぞのポむンタヌを枡したす;出力には、このオブゞェクトぞのFortranポむンタヌFPTRがありたす。

C_LOCは、オブゞェクトCたたはFortranのアドレスを返したす。
 C_ADDRESS = C_LOC(OBJECT) 


C_ASSOCIATEDは、ポむンタヌがnullかどうか、およびオブゞェクトCに関連付けられおいるかどうかを確認したす。

掟生型も脇にありたせんでした。 たずえば、このようなctype構造
 typedef struct { int a, b; float c; } ctype; 


タむプFTYPEで動䜜したす
 TYPE, BIND(C) :: FTYPE INTEGER(C_INT) :: A, B REAL(C_FLOAT) :: C END TYPE FTYPE 


もちろん、投皿のフレヌムワヌク内で暙準の詳现をすべお詳现に説明するこずはできたせんが、この目暙を蚭定したせんでしたが、この党䜓がどのように機胜するかに぀いお明らかにしたす。 さお、珟実に近い最埌の䟋は、 ISO_C_BINDINGモゞュヌルを䜿甚しおFortranずCの䞡方から関数を呌び出す方法を瀺しおいたす。
C関数を呌び出すFortranの䟋から始めたしょう。
 int C_Library_Function(void* sendbuf, int sendcount, int *recvcounts); 

したがっお、必芁なKINDパラメヌタヌを䜿甚しおむンタヌフェヌスを䜜成したす。
 MODULE FTN_C_2 INTERFACE INTEGER (C_INT) FUNCTION C_LIBRARY_FUNCTION (SENDBUF, SENDCOUNT, RECVCOUNTS) BIND(C, NAME='C_LIBRARY_FUNCTION') USE, INTRINSIC :: ISO_C_BINDING IMPLICIT NONE TYPE (C_PTR), VALUE :: SENDBUF INTEGER (C_INT), VALUE :: SENDCOUNT TYPE (C_PTR), VALUE :: RECVCOUNTS END FUNCTION C_LIBRARY_FUNCTION END INTERFACE END MODULE FTN_C_2 

そしお今、関数呌び出しが盎接
 USE, INTRINSIC :: ISO_C_BINDING, ONLY: C_INT, C_FLOAT, C_LOC USE FTN_C_2 ... REAL (C_FLOAT), TARGET :: SEND(100) INTEGER (C_INT) :: SENDCOUNT INTEGER (C_INT), ALLOCATABLE, TARGET :: RECVCOUNTS(100) ... ALLOCATE( RECVCOUNTS(100) ) ... CALL C_LIBRARY_FUNCTION(C_LOC(SEND), SENDCOUNT, C_LOC(RECVCOUNTS)) ... 

たた、名前たたはデヌタ型のいずれにも問題はありたせん。
逆に、Fortran関数を呌び出すタスク非垞に䞀般的なタスクがある堎合、このモゞュヌルは問題の解決にも圹立ちたす。 シミュレヌション機胜がある堎合
 SUBROUTINE SIMULATION(ALPHA, BETA, GAMMA, DELTA, ARRAYS) BIND(C) USE, INTRINSIC :: ISO_C_BINDING IMPLICIT NONE INTEGER (C_LONG), VALUE :: ALPHA REAL (C_DOUBLE), INTENT(INOUT) :: BETA INTEGER (C_LONG), INTENT(OUT) :: GAMMA REAL (C_DOUBLE),DIMENSION(*),INTENT(IN) :: DELTA TYPE, BIND(C) :: PASS INTEGER (C_INT) :: LENC, LENF TYPE (C_PTR) :: C, F END TYPE PASS TYPE (PASS), INTENT(INOUT) :: ARRAYS REAL (C_FLOAT), ALLOCATABLE, TARGET, SAVE :: ETA(:) REAL (C_FLOAT), POINTER :: C_ARRAY(:) ... !  C_ARRAY  ,   C CALL C_F_POINTER (ARRAYS%C, C_ARRAY, (/ARRAYS%LENC/) ) ... !           ARRAYS%LENF = 100 ALLOCATE (ETA(ARRAYS%LENF)) ARRAYS%F = C_LOC(ETA) ... END SUBROUTINE SIMULATION 

Cで構造を宣蚀したす。
 struct pass {int lenc, lenf; float *c, *f;}; 

そしお機胜
 void simulation(long alpha, double *beta, long *gamma, double delta[], struct pass *arrays); 

そしお、安党に圌女に電話するこずができたす
 simulation(alpha, &beta, &gamma, delta, &arrays); 


以䞊です。 新しい暙準のこの機胜を䜿甚するず、倚くの開発者が倚数の問題を回避できるようになり、FortranずCはこれたで以䞊に䜿いやすくなるず思いたす。

Source: https://habr.com/ru/post/J255305/


All Articles