T.B*_*own 5 c++ fortran fortran-iso-c-binding
我试图在用Fortran编写的程序中使用C ++编写的库中的函数。C ++库在一个头文件中进行了汇总,因此,如果您只想在另一个C ++程序中使用它,#include functions.h
我想了解如何在Fortran中执行类似的操作。
根据我的研究,我创建了这个最小可行的示例:
clib / functions.h:
#ifndef ADD_H
#define ADD_H
extern "C"
{
int __stdcall add(int x, int y);
}
#endif
Run Code Online (Sandbox Code Playgroud)
clib / functions.cpp:
extern "C"
{
int __stdcall add(int x, int y)
{
return x + y;
}
}
Run Code Online (Sandbox Code Playgroud)
cinclude.c
#include "clib/functions.h"
Run Code Online (Sandbox Code Playgroud)
cinterface.f95:
module cinterface
use,intrinsic::ISO_C_BINDING
integer(C_INT)::a,b
interface
integer(C_INT) function add(a,b) bind(C,name="add")
use,intrinsic::ISO_C_BINDING
implicit none
!GCC$ ATTRIBUTES STDCALL :: add
!DEC$ ATTRIBUTES STDCALL :: add
integer(C_INT), value ::a,b
end function add
end interface
end module cinterface
Run Code Online (Sandbox Code Playgroud)
main.f90
program main
use cinterface
implicit none
integer :: c
c = add(1,2)
write(*,*) c
end program
Run Code Online (Sandbox Code Playgroud)
生成文件:
FC = gfortran
CC = g++
LD = gfortran
FFLAGS = -c -O2
CFLAGS = -c -O2
OBJ=main.o
DEP = \
cinterface.o cinclude.o
.SUFFIXES: .f90 .f95 .c .o
# default rule to make .o files from .f files
.f90.o : ; $(FC) $(FFLAGS) $*.f90 -o $*.o
.f95.o : ; $(FC) $(FFLAGS) $*.f95 -o $*.o
.c.o : ; $(CC) $(CFLAGS) $*.c -o $*.o
%.o: %.mod
#
main.ex: ${DEP} ${OBJ}
$(LD) ${DEP} ${OBJ} -o prog.exe
#
Run Code Online (Sandbox Code Playgroud)
当我尝试使用Cygwin进行此项目时,出现以下错误:
main.o:main.f90:(.text+0x13): undefined reference to `add'
main.o:main.f90:(.text+0x13): relocation truncated to fit: R_X86_64_PC32 against undefined symbol `add'
collect2: error: ld returned 1 exit status
make: *** [makefile:19: main.ex] Error 1
Run Code Online (Sandbox Code Playgroud)
如何使add
Fortran中的功能起作用?
你已经差不多到那里了。为了使这项工作有效,您需要解决两件事:链接和参数传递约定。
连锁
正如 francescalus 所指出的,Fortran 编译器不理解如何解析 C/C++ 头文件。因此,您的functions.h 和cinclude.c 文件在此示例中不会有任何用处。
不过,不要扔掉你的functions.h。在其中您将 add 函数声明为:
extern "C"
{
int __stdcall add(int x, int y);
}
Run Code Online (Sandbox Code Playgroud)
这extern "C"
是重要的部分。这告诉 g++ 以下代码块中的符号不受所有 C++名称修饰的影响。您将需要与functions.cpp 中的定义相同的内容add
。
extern "C"
{
int add(int x, int y)
{
return x + y;
}
}
Run Code Online (Sandbox Code Playgroud)
完成此操作后,您需要链接的只是functions.o、cinterface.o/mod 和main.o。
参数传递约定
该方法add
声明参数x
并按y
值传递给函数。这是 C/C++ 函数参数的默认行为。另一方面,Fortran 默认通过引用将参数传递给函数/子例程。在 C++ 中,这看起来像int add(int* x, int* y)
. 有两种方法可以解决这个问题。
第一个选项是使用参数的整数指针重新定义 add 函数,并在函数内取消引用它们。
extern "C"
{
int add(int* x, int* y)
{
return *x + *y;
}
}
Run Code Online (Sandbox Code Playgroud)
第二个选项(恕我直言,这是首选选项)是声明 Fortran 接口以按值传递参数。它们没有在add
函数中被修改......为什么通过引用传递它们?如果您选择此选项,那么您的 cinterface.f95 将需要包含以下声明add
:
integer(C_INT) function add(a,b) bind(C,name="add")
use,intrinsic::ISO_C_BINDING
implicit none
integer(C_INT),value::a,b
end function add
Run Code Online (Sandbox Code Playgroud)
value
请注意变量a
和上的附加修饰b
。无论您使用哪个选项,如果我的机器上没有它,我都会打印出 8393540 作为add
函数调用的结果。在解决参数传递约定后,我按预期打印出 3 。
归档时间: |
|
查看次数: |
228 次 |
最近记录: |