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

通过Fortran调用C函数时遇rt_onestep未定义引用问题求助

问题描述

我正在尝试将MATLAB仿真(从Simulink模型生成的C代码)迁移到PSCAD,需要通过Fortran封装函数调用C函数:Fortran脚本定义输入输出变量,传递给C代码完成计算后返回结果到PSCAD。但用Visual Studio将C程序编译为.lib或.dll后,PSCAD编译时提示**undefined reference to rt_onestep_**错误——这个rt_onestep是我编写的C函数,但Fortran找不到它。请问这是编译器兼容性问题吗?该如何解决?


C函数代码

/*
 * Academic License - for use in teaching, academic research, and meeting
 * course requirements at degree granting institutions only.  Not for
 * government, commercial, or other organizational use.
 *
 * File: ert_main.c
 *
 * Code generated for Simulink model 'CInterface0'.
 *
 * Model version                  : 12.6
 * Simulink Coder version         : 23.2 (R2023b) 01-Aug-2023
 * C/C++ source code generated on : Mon Jun  3 13:10:19 2024
 *
 * Target selection: ert_shrlib.tlc
 * Embedded hardware selection: Intel->x86-64 (Windows64)
 * Code generation objectives: Unspecified
 * Validation result: Not run
 */

#include <stddef.h>
#include <stdio.h>            /* This example main program uses printf/fflush */
#include "CInterface0.h" 
#include "rtwtypes.h"              /* Model header file */

void (rt_onestep)(double* freq, double* mod, double* Ia, double* Ib, double* Ic);
void (rt_onestep)(double* freq, double* mod, double* Ia, double* Ib, double* Ic)
{
  CInterface0_U.freq=*freq;
  CInterface0_U.mod=*mod;
  CInterface0_step();
  *Ia=CInterface0_Y.Iabc[0];
  *Ib=CInterface0_Y.Iabc[1];
  *Ic=CInterface0_Y.Iabc[2];
}

PSCAD中的Fortran代码

! ------------------------------------------------------------
      ! Subroutine "Untitled_Fortran_CI"
      ! 
      SUBROUTINE Untitled_Fortran_CI(freq, mod, Ia, Ib, Ic)
      
      REAL freq, mod, Ia, Ib, Ic
            
            ! ----------------------------------------
            ! Intel Interface
            ! ----------------------------------------
#ifdef __INTEL_COMPILER
                  
                  ! --------------------
                  ! Fortran Interface to C Function
                  ! --------------------
                  INTERFACE
                        SUBROUTINE RT_ONESTEP(freq, mod, Ia, Ib, Ic)
                              !DEC$ ATTRIBUTES C :: RT_ONESTEP
                              !DEC$ ATTRIBUTES REFERENCE :: freq
                              !DEC$ ATTRIBUTES REFERENCE :: mod
                              !DEC$ ATTRIBUTES REFERENCE :: Ia
                              !DEC$ ATTRIBUTES REFERENCE :: Ib
                              !DEC$ ATTRIBUTES REFERENCE :: Ic
                              REAL freq, mod, Ia, Ib, Ic
                        END SUBROUTINE
                  END INTERFACE
#endif
            
            ! Call C Function
            CALL RT_ONESTEP(freq, mod, Ia, Ib, Ic)
            
      END

解决方案

这个错误核心是C与Fortran的名称修饰规则不匹配,同时可能伴随编译器兼容性问题,以下是具体解决步骤:

1. 统一C函数的导出规则

C语言默认函数名编译后为小写,但Fortran默认会将调用的外部函数名转为大写并添加下划线(比如RT_ONESTEP会被解析为rt_onestep_)。需要修改C代码,确保函数名导出规则与Fortran期望一致:

  • 添加extern "C"避免C++风格的名称修饰,同时用__declspec(dllexport)标记函数为可导出(Windows平台):
#ifdef _WIN32
#define EXPORT __declspec(dllexport)
#else
#define EXPORT
#endif

#ifdef __cplusplus
extern "C" {
#endif

EXPORT void rt_onestep(double* freq, double* mod, double* Ia, double* Ib, double* Ic);
EXPORT void rt_onestep(double* freq, double* mod, double* Ia, double* Ib, double* Ic)
{
  // 原函数逻辑不变
  CInterface0_U.freq=*freq;
  CInterface0_U.mod=*mod;
  CInterface0_step();
  *Ia=CInterface0_Y.Iabc[0];
  *Ib=CInterface0_Y.Iabc[1];
  *Ic=CInterface0_Y.Iabc[2];
}

#ifdef __cplusplus
}
#endif

2. 修复Fortran接口声明的问题

你的Fortran代码中,接口声明被#ifdef __INTEL_COMPILER包裹,但PSCAD使用的编译器可能不触发该宏,导致接口规则未生效,Fortran只能用默认规则查找函数:

  • 移除#ifdef __INTEL_COMPILER条件判断,确保接口声明始终生效;
  • 注意C函数参数是double*(对应Fortran的双精度实数),需将Fortran中的REAL改为REAL*8,避免类型不匹配:
SUBROUTINE Untitled_Fortran_CI(freq, mod, Ia, Ib, Ic)
      
      REAL*8 freq, mod, Ia, Ib, Ic
            
            ! --------------------
            ! Fortran Interface to C Function
            ! --------------------
            INTERFACE
                  SUBROUTINE RT_ONESTEP(freq, mod, Ia, Ib, Ic)
                        !DEC$ ATTRIBUTES C :: RT_ONESTEP
                        !DEC$ ATTRIBUTES REFERENCE :: freq
                        !DEC$ ATTRIBUTES REFERENCE :: mod
                        !DEC$ ATTRIBUTES REFERENCE :: Ia
                        !DEC$ ATTRIBUTES REFERENCE :: Ib
                        !DEC$ ATTRIBUTES REFERENCE :: Ic
                        REAL*8 freq, mod, Ia, Ib, Ic
                  END SUBROUTINE
            END INTERFACE
            
            ! Call C Function
            CALL RT_ONESTEP(freq, mod, Ia, Ib, Ic)
            
      END

3. 匹配编译器与平台

PSCAD通常使用Intel Fortran Compiler(IFORT)或gfortran,而Visual Studio用MSVC编译C代码,需确保两者的目标平台和ABI兼容:

  • 编译C库时选择x64平台,与PSCAD运行平台保持一致;
  • 优先用Intel ICC编译器编译C代码,减少MSVC与IFORT之间的ABI差异;
  • 编译为**静态库(.lib)**而非动态库(.dll),降低运行时依赖问题,并在PSCAD中正确链接该.lib文件。

4. 强制指定函数别名(可选)

如果C函数导出的名称与Fortran期望的仍不匹配,可在Fortran接口中强制指定C函数的原始名称:

SUBROUTINE RT_ONESTEP(freq, mod, Ia, Ib, Ic)
      !DEC$ ATTRIBUTES C, ALIAS:'rt_onestep' :: RT_ONESTEP
      !DEC$ ATTRIBUTES REFERENCE :: freq
      !DEC$ ATTRIBUTES REFERENCE :: mod
      !DEC$ ATTRIBUTES REFERENCE :: Ia
      !DEC$ ATTRIBUTES REFERENCE :: Ib
      !DEC$ ATTRIBUTES REFERENCE :: Ic
      REAL*8 freq, mod, Ia, Ib, Ic
END SUBROUTINE

你也可以用Visual Studio自带的dumpbin工具查看C库的导出函数名,确认是否匹配:

dumpbin /exports your_library.lib

内容的提问来源于stack exchange,提问作者Usman Ahmed

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 08:58:11