You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

从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;
}

构建步骤及错误:

  1. 编译Fortran代码:gfortran -c test.f90,执行无错误
  2. 链接目标文件: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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 08:22:20