通过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

