能否从C语言调用F77子程序?旧F77子程序的最优替代调用方案
从C调用旧版F77子程序的最优方案
对于无法使用现代Fortran C绑定的旧F77子程序,编写现代Fortran包装器是最可靠、可移植性最高的方案,以下是具体实现和替代方案说明:
1. 现代Fortran包装器方案
用带C绑定的现代Fortran子程序作为中间层,隔离C调用与旧F77代码的差异。C端只需要与标准化的C绑定接口交互,无需处理F77的命名规则、参数传递特性。
示例代码
- 旧F77子程序(典型写法,注意大写命名和隐式类型):
SUBROUTINE OLD_SUB(A, B, N) INTEGER N REAL A(N), B(N) C F77逻辑:将数组A的元素翻倍后存入B DO 10 I=1,N B(I) = A(I) * 2.0 10 CONTINUE RETURN END
- 现代Fortran包装器(带C绑定,统一参数类型和调用规则):
subroutine c_old_sub(a, b, n) bind(C, name="c_old_sub") use, intrinsic :: iso_c_binding implicit none ! 用C兼容的类型声明参数 real(c_float), intent(in) :: a(*) real(c_float), intent(out) :: b(*) integer(c_int), intent(in), value :: n ! 直接调用旧F77子程序(注意编译器对F77名字的大小写处理,通常是自动转大写) call OLD_SUB(a, b, n) end subroutine c_old_sub
C端只需调用c_old_sub,参数用C原生类型:
#include <stdio.h> // 声明包装器的C接口 void c_old_sub(float* a, float* b, int n); int main() { int n = 5; float a[5] = {1.0f, 2.0f, 3.0f, 4.0f, 5.0f}; float b[5]; c_old_sub(a, b, n); for (int i = 0; i < n; i++) { printf("b[%d] = %.1f\n", i, b[i]); } return 0; }
2. 直接适配F77调用约定(不推荐)
如果不想编写包装器,可以手动适配F77的编译器特性,但可移植性差:
- 命名规则:多数F77编译器会将子程序名转为大写(如
OLD_SUB)或添加后缀下划线(如old_sub_),需提前确认目标编译器的命名修饰规则。 - 参数传递:F77默认传引用(即使是整数、实数等基本类型),C端需传递变量地址;多维数组需注意F77是列主序,C是行主序,需手动调整维度顺序。
示例C调用代码(假设编译器将OLD_SUB转为大写且无下划线):
#include <stdio.h> // 声明F77子程序的C接口 void OLD_SUB(float* a, float* b, int* n); int main() { int n = 5; float a[5] = {1.0f, 2.0f, 3.0f, 4.0f, 5.0f}; float b[5]; // F77传引用,需传递n的地址 OLD_SUB(a, b, &n); for (int i = 0; i < n; i++) { printf("b[%d] = %.1f\n", i, b[i]); } return 0; }
3. 工具转换或编译器扩展(备选)
- 部分Fortran编译器提供扩展选项(如
-fc-prototypes),可直接为F77代码生成C兼容的头文件,但依赖具体编译器。 - 用
f2c等工具将F77代码转换为C代码,再直接调用转换后的函数,但生成的C代码可读性差,且可能丢失Fortran特有的特性,仅作为备选方案。
内容的提问来源于stack exchange,提问作者DJames
相关产品推荐
相关产品推荐

