Sza*_*lcs 6 c fortran prototype gfortran
当调用带有参数的 Fortran 函数时logical,特别是使用 gfortran 时,我应该在 C 中使用什么参数类型?gfortran 的记录在哪里?
这是一个示例程序,如果没有警告就无法编译:
\n内容one.f:
subroutine proc1(x)\n logical x\n end\nRun Code Online (Sandbox Code Playgroud)\n内容main.c:
void proc1_(_Bool *x);\n\nint main() {\n _Bool x;\n\n proc1_(&x);\n\n return 0;\n}\nRun Code Online (Sandbox Code Playgroud)\n如果我按如下方式使用 GCC 进行编译,并启用 LTO,我会收到有关函数原型不匹配的警告:
\ngfortran -flto -c one.f\ngcc -flto -c main.c\ngcc -flto main.o one.o\nRun Code Online (Sandbox Code Playgroud)\n我收到的警告:
\nmain.c:2:6: warning: type of \'proc1_\' does not match original declaration [-Wlto-type-mismatch]\n 2 | void proc1_(_Bool *x);\n | ^\none.f:2:22: note: \'proc1\' was previously declared here\n 2 | subroutine proc1(x)\n | ^\none.f:2:22: note: code may be misoptimized unless \'-fno-strict-aliasing\' is used\nRun Code Online (Sandbox Code Playgroud)\n请注意,启用 LTO 允许链接器验证原型之间的参数类型是否匹配。不幸的是,使用 LTO 不是我们的选择。CRAN要求在启用 LTO 的情况下,在没有这些警告的情况下编译提交的代码。
\n我只在尝试使用logical参数时才发现问题。real,integer并且character都很好。
可以要求 gfortran 生成 C 原型,这是它给我的输出:
\ngfortran -flto -fc-prototypes-external -c one.f\nRun Code Online (Sandbox Code Playgroud)\nvoid proc1_ (int_fast32_t *x);\nRun Code Online (Sandbox Code Playgroud)\n在 C 原型中使用int_fast32_t也不起作用。我尝试过的类型都没有,既不是int,也不是_Bool。通常,当原型之间存在类型不匹配时,错误消息会提到类型应该是什么\xe2\x80\x94,但在本例中不是这样。
我怎样才能找到正确的使用类型?
\n为了实现真正的现代 C-Fortran 互操作性,您应该使用模块提供的类型(种类)iso_c_binding并创建您的 Fortran 过程bind(c)。这样你就可以使用logical(c_bool).
在旧风格中,最好的办法是使用整数并在 Fortran 内部传递一个且仅int正确的值。老C没有,是后来加上去的。integerlogicalbool
经过最小的改变:
subroutine proc1(x)
use iso_c_binding
logical(c_bool) x
end
Run Code Online (Sandbox Code Playgroud)
#include <stdbool.h>
void proc1_(bool *x);
int main() {
bool x;
proc1_(&x);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
> gfortran -flto -c one.f
> gcc -flto -c main.c
> gcc -flto main.o one.o
Run Code Online (Sandbox Code Playgroud)
在我的 Linux 和 GCC 7 和 10 上没有发出警告。
或者进一步更改后:
subroutine proc1(x) bind(C, name="proc1")
use iso_c_binding
logical(c_bool), value :: x
end
Run Code Online (Sandbox Code Playgroud)
#include <stdbool.h>
void proc1(bool x);
int main() {
bool x;
proc1(x);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
当然,只有当它确实只是一个输入参数时,才更改为按值传递。
正如 Vladimir F 的回答所解释的,正确且保证可移植的解决方案是创建一个使用 ISO_C_BINDING 的 Fortran 包装器例程。该包装器还可以借此机会创建更惯用的 C 接口,例如使用value说明符按值传递标量。
然而,对于在没有 LTO 的情况下在 GFortran 上运行的快速而肮脏的解决方案(在其他编译器上也有可能,但不能保证),请参阅https://gcc.gnu.org/onlinedocs/gfortran/Internal-representation-of-LOGICAL- Variables.html#逻辑变量的内部表示。也就是说,您可以传递包含1for true 和0for false 的适当大小的 C 整数变量。此处适当的大小意味着除非您使用-fdefault-integer-8或此类编译选项编译了 Fortran 代码,否则 GFortran 默认类型逻辑将为 4 个字节,因此纯 Cint应该很好(或者int32_t如果您真的想确定,尽管我不知道)认为 GFortran 支持 Cint不是 32 位的任何目标)。
这不适用于 LTO 的原因是,虽然上述方法有效,但在 GCC 内部,Fortran LOGICAL 变量几乎与整数相同,但又不完全相同。因此,实际上它们是特殊的整数变量,最大值为 1,最小值为 0,即使它们占用更多空间(由其 kind 参数指定)。所以这种类型不匹配很可能就是它所抱怨的。不幸的是,除了上述通过 ISO_C_BINDING 的正确解决方案外,没有解决此问题的方法。