【问题标题】:Accessing Fortran Common Block from C as Struct从 C 作为结构访问 Fortran 公共块
【发布时间】:2019-08-16 21:38:54
【问题描述】:

我正在尝试在 C 中定义和声明一组结构,然后在 fortran 中与它们进行交互,然后再将它们传递回去以在 C 函数中进行操作。我知道可以通过使用 c 结构和 fortran 通用块来实现互操作性。我尝试了几种方法都没有成功。

限制:使用 cvfortran、f77。转换为较新的格式是不现实的。对于 C,使用 MSVS C 编译器。

这是 cvfortran 手册第 618 页的建议: (http://jp.xlsoft.com/documents/intel/cvf/cvf_pg.pdf)

“举个例子,假设你的 Fortran 代码有一个公共块,名为真的, 如图:"

!DEC$ ATTRIBUTES ALIAS:'Really' :: Really
REAL(4) x, y, z(6)
REAL(8) ydbl
COMMON / Really / x, y, z(6), ydbl

"您可以使用以下外部代码从您的 C 代码中访问此数据结构 数据结构:"

#pragma pack(2)
extern struct {
float x, y, z[6];
double ydbl;
} Really;
#pragma pack()

每当我尝试这个时,我都会收到“未解析的外部符号 _Really 在函数 xxx 中引用,并且无法编译。

CVFortran 手册中的方法:

Fortran

      PROGRAM MYPROG
      !DEC$ ATTRIBUTES ALIAS:'Really' :: Really
      REAL(4) x, y, z
      COMMON / Really / x, y, z

      INTERFACE 
          SUBROUTINE STRUCTFUN()
cDEC$ ATTRIBUTES C, ALIAS:'_StructFun' :: STRUCTFUN  ! for calling C functions
          END SUBROUTINE STRUCTFUN 
      END INTERFACE  
      X = 6.
      Y = 5.
      Z = 0.       

      CALL STRUCTFUN() 
      END PROGRAM

C

#include <stdio.h>

void StructFun(void)
{
    #pragma pack(2)
    extern struct {
    float x, y, z;
    } Really;
    #pragma pack()
    printf("x: %f\n y: %f\n z: %f\n", Really.x, Really.y, Really.z);
    printf("From C \n");

}

然后我尝试了我在下面粘贴的内容,其中我在头文件中定义了一个结构类型,然后尝试将其设置为 c 外部。我还应该提到,我将 C 函数导出为带有 .def 文件的 dll,以便可以从我的 fortran 模块中调用它。这不会产生任何错误,但会为我的所有变量返回零值。

示例程序:

Fortran

      PROGRAM MYPROG
      REAL(4) X,Y,Z
      COMMON / REALLY / X, Y, Z

      INTERFACE 
          SUBROUTINE STRUCTFUN()
cDEC$ ATTRIBUTES C, ALIAS:'_StructFun' :: STRUCTFUN  ! for calling C functions
          END SUBROUTINE STRUCTFUN 
      END INTERFACE  
      X = 6.
      Y = 5.
      Z = 0.       

      CALL STRUCTFUN() 
      END PROGRAM

C 函数


#include "structProg.h"
rtype really_;
void StructFun(void)
{
  printf("x: %f\n y: %f\n z: %f\n", really_.x, really_.y, really_.z);
  printf("From C \n");

}

C 头文件

#include <string.h>
#include <stdio.h>

typedef struct{
    float x;
    float y;
    float z;
} rtype;

extern rtype really_;
extern void StructFun(void);

我知道问这个问题有点牵强,因为我使用的是旧编译器,但我们将不胜感激。

我也试过这里列出的方法:http://www.yolinux.com/TUTORIALS/LinuxTutorialMixingFortranAndC.html

【问题讨论】:

  • 您报告的错误消息似乎与您提供的代码不一致。特别是,它抱怨的外部符号是_Really,但您的代码都没有引用或访问这样的符号。此外,虽然您的 C 代码访问 similar 符号 really_,但它也提供了该符号的定义,因此不应产生此类错误。我们将竭尽全力帮助您使用您正在使用的旧的且有些特殊的工具链,因此您比平常更重要的是提供一个实际证明问题的minimal reproducible example
  • 我将编辑第一个示例的示例,对此感到抱歉。
  • 您的代码不符合 FORTRAN 77。 REAL(4) 是 Fortran 90 语法,数字 4 与 REAL*4 中的 4 不同 stackoverflow.com/questions/838310/fortran-90-kind-parameter INTERFACE 关键字也是 Fortran 90+。
  • 我不确定第一条评论,但谷歌快速搜索显示了 F77 使用 INTERFACE 块的示例。更改类型投诉后,我得到了相同的结果。
  • 您的意思是“对您来说看起来像 F77 的程序”... INTERFACE 绝对是 Fortran 90。您可以查看标签页上链接的标准 stackoverflow.com/tags/fortran/info Compaq Visual Fotran 确实支持 Fortran 90 和文件扩展名 .f 或 .f90 对此根本不重要,它只控制 fiexd 与免费源形式。

标签: c struct fortran language-interoperability fortran-common-block


【解决方案1】:

我不是这里的专家,但错误表明没有集成的“C 和 Fortran”程序。

您在 Fortran 中开发了一些模块,在 C (C++) 中开发了一些模块。您决定它是 C 程序(然后将 main 作为程序入口点)还是 Fortran 程序(然后它具有 Fortran 程序入口点)。

您使用各自的编译器编译 C 模块和 Fortran 模块。这些交付 .obj 或 .o 文件、目标文件。最后将这些链接在一起以创建可执行程序。

你所做的似乎是正确的。但是“未解析的外部符号”错误是 linker 错误。这意味着链接器在目标模块中找不到 Fortran Common 块。

我希望这会有所帮助。

【讨论】:

  • 我认为有这些错误的问题应该直接关闭meta.stackoverflow.com/questions/381483/…
  • 所以在外部符号无法解析的情况下,我需要先编译fortran,然后将目标文件链接到C源代码?我一直在尝试的是编译 C 源代码,导出到 dll,并将其导入库链接到与 fortran 编译器一起的 fortran 源文件。
  • 导出到 DLL 与将 Fortran 和 C 生成的对象链接到单个可执行文件中完全不同!
【解决方案2】:

您更新后的问题与原来的问题不同。现在的问题是:

这不会产生任何错误,但会为我的所有变量返回零值。

那是因为您根本没有访问公共块。尽管在您的头文件中有对象really_ 的外部声明...

extern rtype really_;

...您的 .c 源代码包含对象 really_定义,原因是:

rtype really_;

从技术上讲,这是一个“暂定定义”,但在同一个翻译单元中没有带有初始化程序的定义,指定的对象在该 TU 中定义,并使用所有成员 0 进行初始化。因此,您的 C代码打印出那些零。

此外,还不清楚为什么您希望能够通过名称 really_ 访问 Fortran 公共块 REALLY。您从 CVF 文档中提供的具体示例和这些文档的更广泛的文本都不支持该结论。在 Fortran 端声明的块没有别名,文档让我期望它可以通过其名称的全大写版本在 C 端访问,REALLY

extern struct {
    float x;
    float y;
    float z;
} REALLY;

void StructFun(void) {
    printf("x: %f\n y: %f\n z: %f\n", REALLY.x, REALLY.y, REALLY.z);
    printf("From C \n");
}

特别注意

  • C 区分大小写,而 Fortran 不区分,但 CVF 文档似乎表明默认情况下它会为 Fortran 对象和函数生成大写的外部名称。
  • CVF 文档似乎也暗示它不会通过用下划线装饰 Fortran 对象的外部名称来破坏它们。 (我还没有阅读足够的内容来确定这是否适用于子例程和函数。)
  • 虽然这样做并没有错,但也没有必要为公共块typedef一个结构类型。不过,鉴于数据的性质,对我来说这样做似乎更自然。
  • 请注意,我的示例 C 代码仅提供对象 REALLY(作为外部对象)的声明,而不是定义。
  • 如果您愿意,可以将REALLY 的声明移动到头文件中。如果您要从多个 C 翻译单元访问它,那将是合适的,但如果您只打算在一个翻译单元中使用它,则没有必要。
  • 您也可以将函数声明放在头文件中,但这只有在其他翻译单元中定义的其他 C 函数调用时才有用。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-30
    • 2016-04-28
    • 2012-04-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多