英文:
Can an f77 subroutine be called from C?
问题
如果Fortran子程序是一个旧的F77子程序,那么这种绑定显然不是一个可用的解决方案。最佳替代方法是什么?
英文:
In modern Fortran, we can call a subroutine from C by using C binding. E.g. The Fortran subroutine will look like this
subroutine my_routine(...) bind (C, name="my_routine")
However, if the fortran subroutine is an old f77 subroutine, this binding is presumably not an available solution. What would be the best alternative?
答案1
得分: 5
然而,如果Fortran子例程是一个老旧的f77子例程,这个绑定可能不是一个可行的解决方案。
这取决于情况。现代Fortran在很大程度上与Fortran 77向后兼容。您的F77子例程将不带有bind
属性,但如果您愿意添加一个并使用现代Fortran编译器编译它,那么它很可能会像您期望的那样工作,就像最初为更新的Fortran版本编写的代码一样。
另一方面,C互操作为Fortran带来的是标准化,而不是新的功能。人们几乎与人们使用C一样长时间地从C中调用Fortran例程。
问题在于具体情况取决于系统和编译器。如果您不依赖于C互操作,那么您将需要适应您的Fortran编译器的名称修饰和参数传递约定,以成功地从C代码中调用Fortran编译的函数。这些约定各不相同。以前有很多用于此类活动的工具和文档。我想这些天要找到它可能更难,但其中很多仍然应该有效。
那么,什么是最佳替代方案呢?
这取决于您的具体约束条件。如果您愿意修改Fortran源代码并使用现代编译器编译,那么我至少会从给函数添加bind
属性开始,然后看看情况如何。
英文:
> However, if the fortran subroutine is an old f77 subroutine, this binding is presumably not an available solution.
It depends. Modern Fortran is largely backwards compatible with Fortran 77. Your F77 subroutine will not come with a bind
attribute, but if you're willing to add one and compile it with a modern Fortran compiler then chances are pretty good that it will work just as you expect of code originally written for a newer Fortran version.
On the other hand, what C interop brings to Fortran is standardization, not a new capability. People have been calling Fortran routines from C almost as long as people have been using C.
The issue here is that the specifics are system and compiler dependent. If you don't rely on C interop, then you will need to accommodate your Fortran compiler's name-mangling and argument-passing conventions to successfully call Fortran-compiled functions from C code. These vary. There used to be a fair amount of tools and documentation for such activity. I imagine it's harder to find these days, but much of it should still work.
> What would be the best alternative?
That depends on your specific constraints. If you're up for modifying the Fortran source and compiling with a modern compiler then I'd at least start with adding a bind
attribute to the function, and see how that plays out.
答案2
得分: 5
请记住,如果您正在使用任何相对较新的编译器,那么您很可能已经将代码编译为Fortran 2003-2018。即使像g95这样的已停用编译器也已经具备了自Fortran 2003以来的C-Fortran互操作性。
然而,正如我在John的回答下面也评论过的那样,如果您为它添加了bind(C)
,那么对子程序的现有Fortran调用(作为没有显式接口的外部子程序)将无效。它们在实践中可能会起作用,但对于字符字符串等情况则不会。即使它们能够工作,它们也不符合标准。只有在您关心从Fortran对子程序的现有调用时才会有所影响。
如果您不能完全改动代码 - 如果源代码必须以某种原样保留的原因。您可以始终编写一个使用bind(C)
的包装子程序,然后调用原始子程序。通常情况下这是不必要的,但这是一种可能性。
正如John Bollinger提到的,有多种方法可以在不使用bind(C)
的情况下以系统特定的方式调用Fortran子程序,这在本站的几个问题中都有讨论。符号名称通常会附加(最有可能)或前缀化下划线,或两者都有。还有可能使用两个下划线。符号名称可能使用小写或大写字母。参数将通过引用传递(通过指针)。字符字符串character(*)
将使用一个包含每个字符串长度的隐藏整数参数。
英文:
Remember that you are likely compiling the code as Fortran 2003-2018 anyway, if you are using any reasonably recent compiler. Even discontinued compilers like g95 already had the C-Fortran interop from Fortran 2003.
However, as I also commented under John's answer, if you do add bind(C)
to it, the existing Fortran calls (as an external subroutine without explicit interface) to the subroutine will be invalid. They may work in practice, but won't for character strings, for example. And even if they would work, they would not be standard conforming. That only matters if you care about the existing calls to the subroutine from Fortran.
If you could not touch the code at all - if the source code must remain intact for some reason. You can always write a wrapper subroutine that does use bind(C)
and that calls the original subroutine. Usually that is not unnecessary, but it is a possibility.
As John Bollinger mentions, there are ways how to call the Fortran subroutines without bind(C)
in a system specific way, discussed in several questions on this site. The symbol name would typically have an underscore appended (most likely) or prepended, or both.Two underscores are also a possibility. The symbol name might use either small caps or capital letters. The arguments would be passed by reference (through a pointer). Character strings character(*)
would use a hidden integer argument containing the length of each string.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论