как вызвать фортрановые процедуры из C ++?

Я хочу вызвать фортранскую подпрограмму cbesj.f из моего кода на C ++ и как мне этого добиться?

Вот шаги, которые я сделал:

  1. Загрузите cbesj.f плюс зависимости с веб-страницы netlib amos, http://www.netlib.org/cgi-bin/netlibfiles.pl?filename=/amos/cbesj.f

  2. В исходном каталоге,

    f2c -C ++ PR * .f

    g ++ -c * .c

    ar cr libmydemo.a * .o

  3. [test_cbesj.cpp] [1] и
    [mydemo.h] [2] используются для вызова подпрограммы таким образом,

    g ++ test_cbesj.cpp -lf2c -lm -L. -lmydemo
    это возвращает ошибку:

test_cbesj.cpp :(. text + 0xd6): неопределенная ссылка на `cbesj_ (complex *, float *, long *, long *, complex *, long *, long *) ‘

Как правильно обращаться к подпрограмме cbesj_ в моей проблеме? Спасибо!

Спасибо за Кейси:
Я думаю, что ваш подход самый лучший. Но я все еще виноват, почему? Вот так:

f77 -c *.f

в modemo.h

//File mydemo.h
#ifndef MYDEMO_H
#define MYDEMO_H
#include <stdio.h>      /* Standard Library of Input and Output */
#include "f2c.h"
extern"C" int cacai_(complex *z__, real *fnu, integer *kode, integer *mr,         integer *n, complex *y, integer *nz, real *rl, real *tol, real *el\
im, real *alim);
extern"C" int cairy_(complex *z__, integer *id, integer *kode, complex *ai,         integer *nz, integer *ierr);
extern"C" int casyi_(complex *z__, real *fnu, integer *kode, integer *n,     complex *y, integer *nz, real *rl, real *tol, real *elim, real     \
*alim);
extern"C" int cbesj_(complex *z__, real *fnu, integer *kode, integer *n,     complex *cy, integer *nz, integer *ierr);
extern"C" int cbinu_(complex *z__, real *fnu, integer *kode, integer *n,     complex *cy, integer *nz, real *rl, real *fnul, real *tol, real *el\
im, real *alim);
extern"C" int cbknu_(complex *z__, real *fnu, integer *kode, integer *n, complex *y, integer *nz, real *tol, real *elim, real *alim);
extern"C" int cbuni_(complex *z__, real *fnu, integer *kode, integer *n,     complex *y, integer *nz, integer *nui, integer *nlast, real *fnul, \
real *tol, real *elim, real *alim);
extern"C" int ckscl_(complex *zr, real *fnu, integer *n, complex *y, integer *nz, complex *rz, real *ascle, real *tol, real *elim);
extern"C" int cmlri_(complex *z__, real *fnu, integer *kode, integer *n,     complex *y, integer *nz, real *tol);
extern"C" int crati_(complex *z__, real *fnu, integer *n, complex *cy, real *tol);
extern"C" int cs1s2_(complex *zr, complex *s1, complex *s2, integer *nz, real *ascle, real *alim, integer *iuf);
extern"C" int cseri_(complex *z__, real *fnu, integer *kode, integer *n, complex *y, integer *nz, real *tol, real *elim, real *alim);
extern"C" int cshch_(complex *z__, complex *csh, complex *cch);
extern"C" int cuchk_(complex *y, integer *nz, real *ascle, real *tol);
extern"C" int cunhj_(complex *z__, real *fnu, integer *ipmtr, real *tol, complex *phi, complex *arg, complex *zeta1, complex *zeta2, complex\
*asum, complex *bsum);
extern"C" int cuni1_(complex *z__, real *fnu, integer *kode, integer *n, complex *y, integer *nz, integer *nlast, real *fnul, real *tol     \
, real *elim, real *alim);
extern"C" int cuni2_(complex *z__, real *fnu, integer *kode, integer *n, complex *y, integer *nz, integer *nlast, real *fnul, real *tol     \
, real *elim, real *alim);
extern"C" int cunik_(complex *zr, real *fnu, integer *ikflg, integer *ipmtr, real *tol, integer *init, complex *phi, complex *zeta1, complex\
*zeta2, complex *sum, complex *cwrk);
extern"C" int cuoik_(complex *z__, real *fnu, integer *kode, integer *ikflg,     integer *n, complex *y, integer *nuf, real *tol, real *elim, re\
al *alim);
extern"C" int cwrsk_(complex *zr, real *fnu, integer *kode, integer *n,     complex *y, integer *nz, complex *cw, real *tol, real *elim, real *a\
lim);
extern"C" real gamln_(real *z__, integer *ierr);
extern"C" integer i1mach_(integer *i__);
extern"C" real r1mach_(integer *i__);
extern"C" int xerror_(char *mess, integer *nmess, integer *l1, integer *l2,     ftnlen mess_len);
#endif

в test_cbesj.cpp,

#include "mydemo.h"#include "f2c.h"#include <math.h>
#include <iostream>
#include <stdio.h>
#include <assert.h>
using namespace std;
int main(void)
{
//  double x=86840.;
//int nu=46431,j, err;
complex *z,z__;
z__.r = 3.0;z__.i = 2.0;z = &z__;
cout << z->r << '\t' << z->i << endl;
real *fnu;float fnu__ = 3.0;fnu = &fnu__;
integer *kode ;long int kode__=1;kode=&kode__;
integer *n    ;long int n__=1;n=&n__;
complex *cy;
integer *nz;
integer *ierr;
cbesj_(z, fnu, kode, n, cy, nz, ierr);
cout << cy->r << '\t' << cy->i << endl;

return 0;
}

Затем,

g++ -c -g test_cbesj.cpp
g++ -o test *.o -lg2c
./test
3   2
Segmentation fault (core dumped)
gdb test
GNU gdb (Ubuntu/Linaro 7.4-2012.04-0ubuntu2.1) 7.4-2012.04
Copyright (C) 2012 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"and "show warranty" for details.
This GDB was configured as "i686-linux-gnu".
For bug reporting instructions, please see:
<http://bugs.launchpad.net/gdb-linaro/>...
Reading symbols from /media/Downloads/amos-4/test...done.
(gdb) run
Starting program: /media/Downloads/amos-4/test
3   2

Program received signal SIGSEGV, Segmentation fault.
0x0804b355 in cbesj_ ()
(gdb) frame 0
#0  0x0804b355 in cbesj_ ()
(gdb) frame 1
#1  0x0805a3ca in main () at test_cbesj.cpp:21
21    cbesj_(z, fnu, kode, n, cy, nz, ierr);

Спасибо за ответ Ройгвиба! Хорошие предложения на самом деле. Вот измененный test_cbesj.cpp:

complex z, cy;
float fnu;
long int kode, n, nz, ierr;

z.r = 3.0; z.i = 2.0;
fnu = 3.0;
n = 1; kode = 1;
cout.precision(16);
cbesj_( &z, &fnu, &kode, &n, &cy, &nz, &ierr );
cout << cy.r << '\t' << cy.i << endl;
cout << "nz=" << nz << endl;
cout << "ierr=" << ierr << Lendl;

Нет больше ошибок по сегментам. Но по ряду причин код не работает должным образом:

./test
-1.343533039093018  -1.343533992767334
nz=0
ierr=4

и ответы неверны, и ierr также говорит об этом из исходного кода:

C           NZ     - NUMBER OF COMPONENTS SET TO ZERO DUE TO UNDERFLOW,
C                    NZ= 0   , NORMAL RETURN
C                    NZ.GT.0 , LAST NZ COMPONENTS OF CY SET TO ZERO
C                              DUE TO UNDERFLOW, CY(I)=CMPLX(0.0,0.0),
C                              I = N-NZ+1,...,N
C           IERR   - ERROR FLAG
C                    IERR=0, NORMAL RETURN - COMPUTATION COMPLETED
C                    IERR=1, INPUT ERROR   - NO COMPUTATION
C                    IERR=2, OVERFLOW      - NO COMPUTATION, AIMAG(Z)
C                            TOO LARGE ON KODE=1
C                    IERR=3, CABS(Z) OR FNU+N-1 LARGE - COMPUTATION DONE
C                            BUT LOSSES OF SIGNIFCANCE BY ARGUMENT
C                            REDUCTION PRODUCE LESS THAN HALF OF MACHINE
C                            ACCURACY
C                    IERR=4, CABS(Z) OR FNU+N-1 TOO LARGE - NO COMPUTA-
C                            TION BECAUSE OF COMPLETE LOSSES OF SIGNIFI-
C                            CANCE BY ARGUMENT REDUCTION
C                    IERR=5, ERROR              - NO COMPUTATION,
C                            ALGORITHM TERMINATION CONDITION NOT MET

1

Решение

Я загрузил cbesj (или же zbesj) и связанные файлы из Netlib, но по какой-то причине они не работали с gfortran4.8 (в Linux x86_64). Точнее, cbesj всегда дает ierr=4пока не смог скомпилировать zbesj так как zabs имеет слишком много аргументов (но, пожалуйста, смотрите обновление ниже).


Поэтому я отказался от использования оригинальных кодов AMOS и попытался openspecfun это также основано на AMOS. Я скомпилировал последний просто набрав make (с gfortran), который генерировал libopenspecfun.a и т. д. Затем я сделал следующий код для тестирования zbesj:

#include <cstdio>

extern "C" {
void zbesj_( double *zr, double *zi, double *fnu, int *kode, int *n,
double *Jr, double *Ji, int *nz, int *ierr );
}

int main()
{
int    n, nz, ierr, kode;
double fnu, zr, zi, Jr, Ji;

fnu = 2.5;
zr = 1.0; zi = 2.0;
n = 1; kode = 1;

zbesj_( &zr, &zi, &fnu, &kode, &n, &Jr, &Ji, &nz, &ierr );

printf( "fnu = %20.15f\n", fnu );
printf( "z   = %20.15f %20.15f\n", zr, zi );
printf( "J   = %20.15f %20.15f\n", Jr, Ji );
printf( "nz, ierr = %d %d\n", nz, ierr );

return 0;
}

и составлен как

g++ test_zbesj.cpp libopenspecfun.a -lgfortran

который дает

fnu =    2.500000000000000
z   =    1.000000000000000    2.000000000000000
J   =   -0.394517225893988    0.297628229902939
nz, ierr = 0 0

Так как этот сайт говорит, что ответ -0.394517...+ 0.297628...i, результат zbesj кажется правильным.


[Обновить]

Внимательно читая исходный код, а также сравнивая openspecfunБыло обнаружено, что пользователь должен раскомментировать соответствующие разделы i1mach.f а также r1mach.f (или же d1mach.f) в зависимости от условий машины. Для Linux x86_64, кажется, достаточно раскомментировать раздел, отмеченный

C     MACHINE CONSTANTS FOR THE IBM PC

С этой модификацией cbesj работал правильно с ierr=0; в противном случае это дает ierr=4 потому что некоторые константы по умолчанию 0, Для версии с двойной точностью нам также нужно иметь дело с пользовательским ZABS, чье определение противоречит внутреннему. Интел Фортран (ifort) распознает пользовательский ZABS как таковой и компилирует их успешно (хотя с большим количеством предупреждений), в то время как gfortran прекращает компиляцию с синтаксической ошибкой (предполагая, что она является внутренней). openspecfunc избегает этой проблемы, переписав все ZABS с внутренним. Во всяком случае, с вышеуказанными модификациями оба cbesj а также zbesj работал правильно (как и ожидалось).


[Обновление 2]

Оказалось, что с использованием версии BLAS d1mach.f, r1mach.f, а также i1mach.fвсе становится еще проще, потому что они определяют машинно-зависимые константы автоматически, и нам не нужно изменять коды вручную. Пожалуйста, смотрите Netlib / FAQ страница для деталей. То же самое относится и к SLATEC (например, это страница).

wget http://www.netlib.org/blas/i1mach.f
wget http://www.netlib.org/blas/r1mach.f
wget http://www.netlib.org/blas/d1mach.f
2

Другие решения

Других решений пока нет …

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector