Portál AbcLinuxu, 30. dubna 2024 21:13

Interface mezi C++ a F77

6.3.2008 10:35 | Přečteno: 1152× | Výběrový blog | poslední úprava: 10.6.2008 17:33

Jednoduchy příklad interface mezi C++ a f77

Minulý víkend jsem za po dlouhé době potřeboval udělat interface mezi kódem ve fortranu a kódem v C++. Jelikož jsem to již dlouho nedělal, chvíli mi trvalo, než jsem si vzpomněl, jak to udělat (neměl jsem přístup na net; při této příležitosti jsem si zas uvědomil, že bez netu jsem jako bez ruky :-( - tedy co se programování týče). Poté, co se mi to zadařilo, jsem se rozhodnul udělat si jednoduchý prográmek pro přístě, až zas budu bez netu a budu vzpomínat, jak se to dělá. Vše níže uvedené platí pro kompilátor gcc.

Volání fortranovské rutiny z C++ je vcelku jednoduché, stačí funkci deklarovat jako externí, název je stejný jako ve fortranu, ale přídáme podtržítko. Případný parameter předáme pomocí jeho adresy:

extern "C" {void vypisparam_(int* cislo);}
...
vypisparam_(&mojeCislo);

Obvykle ale potřebujeme víc. Velmi často je potřeba nějak přistupovat k proměnným ve fortranovských common blocích. Mějme následně definovaný common blok a jednoduchý fotranovský prográmek:
test.inc:

       DOUBLE PRECISION dp1,dp2
       INTEGER int1
       COMMON/MYTEST/dp1,dp2,int1
test.f:
      PROGRAM TEST
      INCLUDE 'test.inc'
      CALL NASTAV
      CALL VYPIS
      CALL VYPISPARAM(20)
      CALL VYPIS
      END

      SUBROUTINE NASTAV
      INCLUDE 'test.inc'
      PRINT*,'Rutina Nastav - nastavuji parametry'
      dp1 = 1.D0
      dp2 = 3.5D0
      int1 = 10
      END

      SUBROUTINE VYPIS
      INCLUDE 'test.inc'
      PRINT*,"Rutina Vypis:"
      PRINT*,'dp1 = ',dp1
      PRINT*,'dp2 = ',dp2
      PRINT*,'int1 = ',int1
      END

      SUBROUTINE VYPISPARAM(a)
      INCLUDE 'test.inc'
      INTEGER a
      dp1 = a
      dp2 = a
      int1 = a
      PRINT*,'Rutina VypisParam:'
      PRINT*,'a=',a
      END
Common blok bude v C++ reprezentovat struktura. Proměnné v common bloku jsou uloženy v paměti za sebou. Inicializace tedy probíhá tak, že se ukazateli na strukturu v C++ předá adresa první proměnné common bloku z fortranu. Je proto nutné, aby proměnné ve struktuře byly stejného typu a ve stejném pořadí jako ve fortranu (pro vícerozměrná pole pak ješte je nutno dát pozor indexy). O vrácení adresy common bloku se nám postará jednoduchá fortranovská funkce:
      FUNCTION common_block_address(common_block_name)
      INCLUDE 'test.inc'
      CHARACTER*(*) common_block_name
      INTEGER common_block_address
      INTEGER aaadress
      IF(common_block_name.EQ.'MYTEST')THEN
         common_block_address = adress(dp1)
      ELSE
         PRINT*,'Neexistujici common block'
      ENDIF
      RETURN
      END
Jednoduchý prográmek v C++, který volá rutiny fortranovského kódu a pracuje s proměnnými v common bloku, by mohl vypadat takto (v C++ by tedy bylo vhodnejší, abychom byli objektoví:-), vytvořit objekt, který by reprezentoval fortanovský kód):
#include <iostream>

double loc_dp1,loc_dp2;
int loc_int1;


struct MyTest_t{
  double dp1,dp2;
  int int1;
};

extern "C" {
  void nastav_();
  void vypis_();
  void vypisparam_(int* cislo);
}

extern "C" void* adress_(void* var){
  return var;
}

extern "C" void* common_block_address_(char*,int len);

MyTest_t* fMyTest;
void InitCommonBlock(){
  fMyTest = (MyTest_t*)common_block_address_("MYTEST",6);
}

void LocalParToFor(){
    fMyTest->dp1 = loc_dp1;
    fMyTest->dp2 = loc_dp2;
    fMyTest->int1 = loc_int1;
}

void ForToLocalPar(){
    loc_dp1 = fMyTest->dp1;
    loc_dp2 = fMyTest->dp2;
    loc_int1 = fMyTest->int1;
}

int main(){
  int aaa = 100;
  InitCommonBlock();
  nastav_();
  vypis_();
  ForToLocalPar();
  std::cout << "loc_dp1 je " << loc_dp1 << std::endl;
  std::cout << "loc_dp2 je " << loc_dp2 << std::endl;
  std::cout << "loc_int1 je " << loc_int1 << std::endl;
  vypisparam_(&aaa);
  loc_dp1 = 4.5;
  loc_dp2 = 8.3;
  loc_int1 = 15;
  LocalParToFor();
  vypis_();
  return 0;
}
Vše kompilujeme pomocí g++ a poté slikujeme dohromady společně s knihovnou gfortan, u mě např. takto:
g++ common_block_address.o interface.o test.o -L/usr/lib/gcc/i386-redhat-linux/4.3.0/ -lgfortran        

Hodnocení: 100 %

        špatnédobré        

Tiskni Sdílej: Linkuj Jaggni to Vybrali.sme.sk Google Del.icio.us Facebook

Komentáře

Nástroje: Začni sledovat (0) ?Zašle upozornění na váš email při vložení nového komentáře. , Tisk

Vložit další komentář

6.3.2008 11:14 anicka | blog: ze_zivota
Rozbalit Rozbalit vše Re: Interface mezi C++ a F77
Odpovědět | Sbalit | Link | Blokovat | Admin
Hezky clanek a pekne osklive dejavu. Staci nad clankem jen trochu privrit oci a predstavim si zdrojaky octave... :-)
^D
6.3.2008 13:55 Let_Me_Be | skóre: 20 | blog: cat /proc/idea/current | Brno
Rozbalit Rozbalit vše Re: Interface mezi C++ a F77
Odpovědět | Sbalit | Link | Blokovat | Admin
Sice nechapu co to dela ve vyberu, ale jinak dobry zapisek.
Linked in profil - Můj web - Nemůžete vyhrát hádku s blbcem. Nejdřív vás stáhne na svoji úroveň a pak ubije zkušenostmi.

ISSN 1214-1267, (c) 1999-2007 Stickfish s.r.o.