Ошибка сегментации возникает в начале подпрограммы, когда код C вызывает подпрограмму Fortran

У меня есть C ++ код в файле test-Q.cpp которая вызывает подпрограмму Fortran в файле getqpf.F, В файле test-Q.cppЯ объявил код на Фортране как внешний, и я вызываю функцию, используя getqpf_() соглашение об именовании. gcc а также gfortran компиляторы используются в GNU / Linux.

Вот фрагмент из верхней части файла C ++:

extern "C" {
void  getqpf_  (double *tri,
int nsamp,
int lwin,
int nfreqfit,
double dt,
float null,
int L2,
double df,
double *qq,
double *pf,
double *ampls,
double *work1,
double *work2,
double *work3,
double *work4,
int mem,
int morder,
int nfs,
double *xReal,
double *xImag,
double *xAbs,
double *x1,
int cen,
int top,
int bot,
float cut,
int nfst,
int raw);

} // end

Вот соответствующий фрагмент из файла Fortran:

   subroutine getqpf (tri, nsamp, lwin, nfreqfit, dt, null, L2, df,
1                   qq, pf, ampls, work1, work2, work3, work4,
2                   mem, morder, nfs, xReal, xImag, xAbs, x1,
3                   cen,top,bot, cut,nfst,raw)integer  morder, lwin, nsamp, nfreqfit, delay, nfs

real     tri(*)
real     qq(*), pf(*), ampls(*)

real * 8 work1(*), work2(*), work3(*), work4(*)
real * 8 xReal(*), xImag(*), xabs(*), x1(*)

real * 8 dt8, cut8, df8
real     null, cut
integer  nfst
logical  mem, L2, cen, top, bot, rawinteger nf

C program logic code starts here
nf = nfreqfit
delay = 0
dt8  = dt
cut8 = cut

Код Фортрана вызывает другие функции C-кода. В GNU / Linux используется gfortran а также gcc компиляторы, которые я скомпилировал и связал все файлы следующим образом:

 g++ -c test-Q.cpp -I./boost/boost_1_52_0/ -g
gcc -c paul2.c -g
gcc -c paul2_L1.c -g
gcc -c paul6.c -g
gcc -c paul6_L1.c -g
gcc -c fit_slope.c -g
gfortran -c getqpf.F -g
g++ -o test-Q test-Q.o paul2.o paul2_L1.o paul6.o paul6_L1.o fit_slope.o getqpf.o -g

Хотя я могу успешно построить бинарный файл, на линии возникает ошибка nf = nfreqfit, Он расположен в самом верху файла Фортрана. Бег gdb на двоичный файл выдает следующий вывод:

Program received signal SIGSEGV, Segmentation fault.
0x0000000000406fd3 in getqpf (tri=..., nsamp=Cannot access memory at address 0x3e9
) at getqpf.F:44
44        nf = nfreqfit

Что здесь происходит, и почему существует ошибка? Похоже, что память неправильно передается между кодом C ++ и кодом Fortran.

ОБНОВИТЬ

Как упоминает IanH в ответе ниже, проблема заключается в том, что аргументы не передаются по ссылке. Используя C ++, функция должна быть объявлена ​​как:

 extern"C" {
void  getqpf_  (float *tri,
int &nsamp,
int &lwin,
int &nfreqfit,
float &dt,
float &null,
int &L2,
float &df,
float *qq,
float *pf,
float *ampls,
double *work1,
double *work2,
double *work3,
double *work4,
int &mem,
int &morder,
int &nfs,
double *xReal,
double *xImag,
double *xAbs,
double *x1,
int &cen,
int &top,
int &bot,
float &cut,
int &nfst,
int &raw);

} // end

Обратите внимание на наличие амперсандов. Затем функция может быть вызвана в коде как:

getqpf_ (tri,
nsamp,
lwin,
nfreqfit,
dt,
null,
L2,
df,
qq,
pf,
ampls,
work1,
work2,
work3,
work4,
mem,
morder,
nfs,
xReal,
xImag,
xAbs,
x1,
cen,
top,
bot,
cut,
nfst,
raw);

Обратите внимание, что такие переменные, как nsamp объявлены как int nsamp = 1001,

0

Решение

Поддерживая рекомендацию M.S.B. относительно использования совместимости F2003 с C, обратите внимание, что вашей конкретной проблемой является несоответствие прохода по ссылке / проходу по значению (что по-прежнему необходимо учитывать даже при использовании взаимодействия C). Типичные реализации Fortran передают все аргументы по ссылке, в то время как в C (++) по умолчанию используется значение. Что касается C ++, обратите внимание, что все аргументы int и float, а также некоторые из двойных аргументов не имеют спецификатора указателя (*). Эти аргументы передаются по значению — но на стороне Фортрана нет ничего, что указывало бы на это. До F2003 это обычно делалось с использованием специальных директив компилятора в коде Фортрана.

При использовании взаимодействия C в F2003 соглашение о передаче по умолчанию для аргументов процедур с атрибутом BIND (C) является ссылкой. Аргументы, которые передаются по значению, должны иметь атрибут VALUE в своем объявлении.

2

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

Я рекомендую использовать Fortran ISO C Binding. Здесь есть примеры на Stackoverflow и в руководстве по gfortran. Он является частью языкового стандарта Fortran 2003, а до этого — Технического отчета для Fortran 95. Это делает его переносимым для компилятора и платформы. Вам не нужно беспокоиться о соглашениях о вызовах, специфичных для компилятора, или искажениях имен.

2

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