【问题标题】:Calling C function from Fortran with pointers使用指针从 Fortran 调用 C 函数
【发布时间】:2017-01-06 17:57:34
【问题描述】:

我正在尝试用 C 语言创建一个从 Fortran 调用的函数。第一件事。 fortran代码是用f77编译的,c是用gcc编译的。两者都被编译成 .so 库。 c 函数将读取设备上由 fortran 指定的地址和大小的内存。我能够看到传递给 c 的地址和大小,但是我无法在 c 函数中填充数据并将其返回给 fortran。请参阅下面的相关代码。我的假设是数据变量的内存分配或指针语法有问题。

C

void copymemory_( uint32_t *addr, int *size, uint8_t *data )
{

    int i;
    printf("addr %x \n", *addr);
    printf("size %i \n", *size);

    for ( i = 0; i<*size; i++)
    {
        *data[i] = i;
        printf("memory %i \n",*data[i]);
    }

}

Fortran

integer memory(4)
call copymemory(z'dead', 4, memory)

DO i = 1,memsize
   call printf(memory(i))
END DO

【问题讨论】:

  • 您为什么认为有问题?会发生什么?在 Fortran 方面,memsizeprintf 是什么,z'dead' 在哪里做什么?在C端,为什么uint8_t?为什么不能使用标准的 Fortran-C 互操作性?
  • 好吧,伙计,这在很大程度上取决于调用约定...我一生中从未编写过fortran代码,但我现在就试试
  • 任何错误信息?哪个?打印错误的结果?它们长什么样子?
  • printf,是一个只打印到屏幕的函数。 memsize 是一个等于 4 的整数,在 c 函数中打印数组中的值后,可执行文件将崩溃,实际错误是进程 id 由于信号 11 而死亡,并留下了核心转储。
  • 不要理会这些描述。编辑问题并将您拥有的内容复制到此处,这样会更清楚。

标签: c pointers fortran


【解决方案1】:

我对你的代码有几点看法。

请提供可编译的代码并描述该确切代码的输出!

这包括用于标准标头的#include,如果您希望人们调试您的代码,请让他们轻松一些,这样他们就不必搜索您省略了哪些行,因为它们对您来说似乎“显而易见”。只需粘贴所有内容。从这里复制代码应该可以编译!

即使您的代码的可执行部分也无法在我的编译器中编译。我不得不将*data 更改为data。你确定你复制了你的实际代码吗?

cfun.c: In function ‘copymemory_’:
cfun.c:13:9: error: invalid type argument of unary ‘*’ (have ‘int’)
         *data[i] = i;
         ^
cfun.c:14:31: error: invalid type argument of unary ‘*’ (have ‘int’)
         printf("memory %i \n",*data[i]);
                           ^

您的 Fortran 代码包含对某个 printf 子例程的调用。这是在哪里定义的?它是否存在于您的实际代码中?我怀疑是这样。请始终将完整且可编译的代码复制到 StackOverflow。

所以在修复明显的你现在的代码之后是:

#include <stdio.h>
#include <stdint.h>

void copymemory_( uint32_t *addr, int *size, uint8_t *data )
{

    int i;
    printf("addr %x \n", *addr);
    printf("size %i \n", *size);

    for ( i = 0; i<*size; i++)
    {
        data[i] = i;
        printf("memory %i \n",data[i]);
    }

}


implicit none

integer :: memsize = 4

integer memory(4)
integer i

call copymemory(z'dead', 4, memory)

DO i = 1,memsize
   print *, (memory(i))
END DO

END

它不会崩溃,但 Fortran 中的 memory 包含垃圾。必须这样做,因为它是 integer,而您在 C 中将其视为 int8_t

因此,要么将其视为 C 中包含四个整数的数组,要么逐字节复制它,但是您必须传递正确的字节数才能复制。根据您的描述,不清楚您的意图是哪一种,所以我只展示一种可能性:

void copymemory_( uint32_t *addr, int *size, uint32_t *data )

那么输出是正确的:

> gfortran-4.10 -fsanitize=address cfun.c ffun.f90 
> ./a.out 
addr dead 
size 4 
memory 0 
memory 1 
memory 2 
memory 3 
           0
           1
           2
           3

【讨论】:

  • 经过更多研究,我发现实际上没有适合我的目的的解决方案。您提供的解决方案是正确的,如果我不使用 f77 编译器,它会起作用。 f77 不允许从 c 传递到 fortran,并且使用您提供的代码,fortran 数组中总是有垃圾。如果我可以使用 f90,那么您提供的解决方案将起作用。
  • 每个编译器都有自己的调用约定 基本上所有F77编译器都允许这样做,但是没有“F77编译器”,有很多不同的编译器,你必须研究手册找出如何正确地做到这一点。这不是 F77 与 F90,这是一种编译器与不同的编译器。我的解决方案不是标准的 F90,它是 gfortran 特定的。没有标准的 F90 解决方案,标准的 C-Fortran 互操作性是 F2003。
猜你喜欢
  • 2016-01-01
  • 2019-06-19
  • 1970-01-01
  • 2011-01-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多