从C调用含Fortran内在函数的Fortran例程:问题与解决方法
问题:从C调用依赖Fortran内在函数的例程时出现未定义引用错误
我尝试编写一个可被C程序调用的Fortran例程,Fortran代码编译正常,但链接C代码与Fortran目标文件时,出现Fortran内在例程未定义引用的错误。请问是否可以编写这样的Fortran代码或C接口,让调用Fortran内在函数的Fortran函数能被C调用?如果可以,该如何实现?
我的Fortran代码(test.f90):
module test use, intrinsic :: iso_c_binding, only : c_double implicit none contains function getRand() bind(c) real(c_double) :: getRand call random_number(getRand) end function getRand end module test
C调用代码(main.c):
extern double getrand(); int main(){ double r = 0.0; r = getrand(); return 0; }
构建步骤及错误:
- 编译Fortran代码:
gfortran -c test.f90,执行无错误 - 链接目标文件:
gcc test.o main.c,报错如下:
/usr/bin/ld: testmodule.o: in function `getrand': testmodule.f90:(.text+0x15): undefined reference to `_gfortran_random_r8' collect2: error: ld returned 1 exit status
环境:Windows WSL 2上的Ubuntu 20.04.1系统,gfortran与gcc版本为11.3.0,链接器为GNU ld 2.38。
解决方案
完全可以实现,你的代码逻辑本身没有问题,链接错误的核心原因是gcc作为链接器时,不会自动引入Fortran运行时库——Fortran内在函数(比如random_number)的具体实现都在gfortran的运行时库中,必须显式链接才能找到这些符号。
方案1:用gfortran完成最终链接
gfortran作为链接器时,会自动处理Fortran运行时库的依赖,直接执行:
gfortran test.o main.c -o main
或者分步编译C代码后再链接:
gcc -c main.c gfortran test.o main.o -o main
方案2:用gcc手动链接Fortran运行时库
如果一定要用gcc做链接,需要显式指定链接gfortran库:
gcc test.o main.c -lgfortran -o main
额外优化建议
- 随机数初始化:当前代码调用
random_number前没有初始化随机种子,每次运行程序都会生成完全相同的随机序列。可以在Fortran函数中添加种子初始化逻辑,示例如下:function getRand() bind(c) real(c_double) :: getRand integer, save :: is_initialized = 0 integer :: seed_size integer, allocatable :: seed(:) ! 仅初始化一次种子 if (is_initialized == 0) then call random_seed(size=seed_size) allocate(seed(seed_size)) ! 用自定义序列生成种子,也可以替换为系统时间相关的逻辑 seed = 12345 + 37*(/(i, i=1, seed_size)/) call random_seed(put=seed) deallocate(seed) is_initialized = 1 end if call random_number(getRand) end function getRand - 命名兼容性:你的C代码中使用
getrand()是正确的,gfortran中bind(c)会将Fortran函数名转为小写。如果使用其他Fortran编译器,可能需要注意命名规则的差异,但gfortran下无需额外调整。
内容的提问来源于stack exchange,提问作者Justin
相关产品推荐
相关产品推荐

