GNU Fortran - 控制符号案例

Tom*_*Tom 6 fortran gfortran

有没有办法控制GNU Fortran 4.8发出的符号?

较旧的版本(例如3.4)分别使用了源和大写的情况-fcase-lower,-fcase-preserve并且-fcase-upper强制小写,但这些似乎已被丢弃.是否有一些新的控制方式?

编辑

我正在尝试将一个大型的,混合的C/Fortran代码库从英特尔编译器移植到GNU编译器.

我知道我们可以BIND(C, name='...')用来给出一个特定于案例的符号名称.但是,这还有其他影响.考虑这个C函数:

void print(char *str, size_t len) {
    for(int ii = 0; ii < len; ii++) {
        putchar(str[ii]);
    }
    putchar('\n');
}
Run Code Online (Sandbox Code Playgroud)

我们可以从这样的Fortran程序中调用它:

program test
    implicit none
    interface
        subroutine printstr(str)
            character :: str(*)
        end subroutine
    end interface

    call printstr("Hello, world.");
end
Run Code Online (Sandbox Code Playgroud)

如果C函数名称不是全部小写(PrintStr比如说),那么我们可能会尝试修复Fortran程序,如下所示:

program test
    implicit none
    interface
        subroutine printstr(str) bind(C, name='PrintStr')
            use iso_c_binding
            character :: str(*)
        end subroutine
    end interface

    call printstr("Hello, world.");
end
Run Code Online (Sandbox Code Playgroud)

但这不起作用,因为bind(C, ...)更改了如何处理字符串参数和不再提供length参数(我不确定这是否会导致堆栈损坏或只是缓冲区溢出 - 给出的示例总是来自缓冲区的segfaults超限).

我想现在可能是一个关于如何解决这个问题的新问题的时候了.

小智 5

We have searched high and low for exactly this functionality. In particular, to have case preserved WITHOUT Bind'C. The extreme "shove" introduced by the powers that be to insist on Bind'C is a terrible outcome for many important circumstances, and especially legacy code, and most especially on Windows.

There is NO CHEAP way of porting legacy or Intel etc mixed language code to gFortran, since, as far as we can tell, many years ago the keepers of GNU Fortran explicitly decided they would NOT keep "preserve-case" or anything like it (I forget the bug report, but you can search for it) saying that there was not sufficient interest ... I must say that sounds a little preposterous, as anyone working in a mixed language environment in Windows will almost surely need a preserve case facility with high frequency. This is required in VBA/Fortran for DLL's, required in accessing WinAPI s/r's etc etc., and where Bind'C/ISO causes more problems than fixes.

Similarly, they decided NOT to have an ALIAS or something like that attribute in the compiler directives.

Thus, the ONLY mechanism in gFortran (that we know of) that permits preserving case is Bind'C, which is a DISASTER for a variety of reasons, most especially for passing fixed len strings of len > 1.

We use two different, and highly unsatisfactory, solutions styles for mixed lang/interop with gFortran:

  1. The MUST PRESERVE case case, such as when interfacing to a WinAPI:

    界面 !函数 w32_GetWindowTextW(hWnd, lpString, nMaxCount) 绑定(C,name="GetWindowTextW") !!来自 c:\Windows\System32\User32.dll !使用,内在 :: ISO_C_BINDING,仅:c_IntPtr_t,c_Size_t,c_Int,c_Ptr,c_Char!!GCC$ 属性 STDCALL :: w32_GetWindowTextW、hWnd、lpString、nMaxCount !整数(c_Int)::w32_GetWindowTextW 整数(c_IntPtr_t),值::hWnd!注意:这应该是一个Win句柄,这似乎是ISO等效的Character(Kind=c_Char) :: lpString(*) Integer(c_Int), Value :: nMaxCount!注意:这应该是 WinAPI int 类型,这似乎是 ISO 等效的 End Function w32_GetWindowTextW !终端接口

这里,保留大小写是必不可少的,否则接口将无法在 WinAPI 中找到入口点。此外,Bind'C 允许使用别名,而这在 GCC FPP 中由于某种奇怪的原因而无法使用。

GCC 编译器指令需要克服 Bind'C 对调用约定的破坏/更改,并将其恢复为 STDCALL,按照 WinAPI(以及 VB、Excel/VBA 等)的要求。

然而,看看处理 lpString var 所需的“狗早餐”,它现在必须是一个向量或 Len=1。这是一个非常昂贵的重写(不仅在声明中,而且在使用这些变量的所有地方,至少必须添加一个额外的层来将 Len=1 字符数组转换为原始的固定长度字符变量)。

  1. 保留大小写会“很好”,但使用全部小写会“更便宜”,例如使用 VBA/Fortran 互操作来创建 DLL 作为 Excel 加载项。

旁白:以下内容依赖于我们自己的库中 erf 的自定义实现,但相当好的一个可以作为内在函数使用。

您可以使用 Bind'C 并保留大小写(以及所有“字符串含义”),例如

Function Erf_Math_BindC_XL(x) bind(C,name="Erf_Math_BindC_XL")
!
Use ARTMathFuncsMod, Only: MathErf  ! Proprietary alternative to Fortran2008 intrinsic Erf()
!
!GCC$ ATTRIBUTES DLLEXPORT, STDCALL :: Erf_Math_BindC_XL
!
Real*8                   :: Erf_Math_BindC_XL
!
Real*8, Intent(In)       :: x
!
Erf_Math_BindC_XL = MathErf(x)
!
End Function Erf_Math_BindC_XL
Run Code Online (Sandbox Code Playgroud)

相比之下,您可以使用:

Function Erf_Math_XL(x)
!
Use ARTMathFuncsMod, Only: MathErf  ! Proprietary alternative to Fortran2008 intrinsic Erf()
!
!GCC$ ATTRIBUTES DLLEXPORT, STDCALL :: Erf_Math_BindC_XL
!
Real*8                   :: Erf_Math_XL
!
Real*8, Intent(In)       :: x
!
Erf_Math_XL = MathErf(x)
!
End Function Erf_Math_XL
Run Code Online (Sandbox Code Playgroud)

但是,如果您直接使用 gFortan 进行编译,条目名称将被修饰并看起来像_erf_math_xl@4.

因此,如果您已经有一个依赖于“Erf_Math_XL”的 VBA 声明,那么它将失败。

现在,您可以重写所有 VBA 方面...非常昂贵,并且每次更改 arg 列表时“@nn”都会更改,因此实际上“几何上更昂贵”。

相比之下,如果在 gFortran 端使用 -fno-underscore 和 -mrtd,那么条目名称将简单地变为erf_math_xl. 好的,所以它不是保留大小写,但它们都是小写,并且“未修饰”。与将许多固定 len 字符串重写为 len=1 数组等相比,这可以以更便宜的方式处理。

然后在 VBA 端,Function/Sub 声明确实允许 ALIAS,因此“案例问题”是一个相对简单的“编辑/替换宏”


jan*_*neb 1

gfortran 中没有相应的命令行选项。也就是说,GFortran 支持 ISO_C_BINDING 功能,因此您可以将符号重命名为 C 中有效的任何符号,例如:


subroutine foo (a) bind(C, name="FoOoF")
  use iso_c_binding
  integer(C_int) :: a
  a = 42
end subroutine foo
Run Code Online (Sandbox Code Playgroud)

  • 实际上,情况似乎比这更糟糕,因为“BIND(C...)”也改变了调用约定,例如字符串的处理方式。 (2认同)