2

我正在尝试修改此代码作为备份的要点)以使其与 gfortran-gcc 兼容。

  • 我删除了[VALUE]标签
  • POINTER-fcray-pointergfortran 的标志一起使用,而不是[REFERENCE]标签
  • 删除了__stdcall ,因为尝试了#define __stdcall __attribute__((stdcall))导致warning: ‘stdcall’ attribute ignored [-Wattributes] 现在这就是我所拥有的:

C代码CMAIN.C

#include <stdio.h>

extern int FACT_(int n);
extern void PYTHAGORAS_(float a, float b, float *c);

main()
{
    float c;
    printf("Factorial of 7 is: %d\n", FACT_(7));
    PYTHAGORAS_(30, 40, &c);
    printf("Hypotenuse if sides 30, 40 is: %f\n", c);
}

FORTRAN 代码FORSUBS.FOR

  INTEGER*4 FUNCTION Fact (n)
  INTEGER*4 n 
  INTEGER*4 i, amt
  amt = 1
  DO i = 1, n
    amt = amt * i
  END DO
  Fact = amt
  END

  SUBROUTINE Pythagoras (a, b, cp)
  REAL*4 a
  REAL*4 b
  POINTER (cp, c)
  REAL*4 c
  c = SQRT (a * a + b * b)
  END

Makefile:_

all:
    gfortran -c FORSUBS.FOR -fcray-pointer
    gcc -c CMAIN.C
    gfortran -o result.out FORSUBS.o CMAIN.o  
    rm -rf *.o

clean :
    rm -rf *.out *~ *.bak *.o

但是我仍然收到错误:

CMAIN.o:在函数“main”中:

CMAIN.C:(.text+0x1d): 未定义对“FACT_(int)”的引用

CMAIN.C:(.text+0x4c): 未定义引用`PYTHAGORAS_(float, float, float*)'

如果您能帮助我知道,我将不胜感激:

  • 问题是什么,我该如何解决?
  • 修改原始代码以使 gcc-gfortran 与最小更改兼容的最佳方法是什么。

PS1。也在Reddit上分享。 PS2。操作系统和编译器规范与这个问题相同。

4

2 回答 2

4

Fortran 通过引用传递变量,如任何 Fortran 到 C 教程的第一句话中所述。那么你:

  1. 不能只删除[VALUE],您应该添加现代 VALUE 属性或更改 C 代码以传递指针。

  2. 不应在 的 Fortran 端使用指针,而应将其[REFERENCE]删除。

  3. 为您的编译器使用实际名称修饰,这些天通常subroutine_name_(附加下划线,名称为小写)或使用现代bind(C, name="binding_name")属性。

没有现代 Fortran,但有VALUE(它只是一个没有的 PITA):

  INTEGER*4 FUNCTION Fact (n)
  INTEGER*4, VALUE :: n 
  INTEGER*4 i, amt
  amt = 1
  DO i = 1, n
    amt = amt * i
  END DO
  Fact = amt
  END

  SUBROUTINE Pythagoras (a, b, c) bind(C)
  REAL*4, VALUE :: a
  REAL*4, VALUE :: b
  REAL*4 c
  c = SQRT (a * a + b * b)
  END

而不仅仅是将您的 C 名称更改为小写 ( pythagoras_, fact_) ... 使用该VALUE属性,您无需介绍您在其他答案中看到的所有 C 临时文件。是正常工作所bind(C)必需的。VALUE它将使您免于重写调用 Fortran 过程的代码。

为了获得最佳的现代体验,请使用bind(C,name="any_name_you_want")设置确切的链接符号名称。

于 2018-12-02T23:43:15.480 回答
3

除了我的顶级评论外,Fortran 通过引用传递,因此您必须修改.c.for文件。

下面的代码有效。可能有一种更简单的方法来声明事物,但这应该[至少]让你走得更远。警告:自从 Fortran IV 时代以来,我没有做过太多的 fortran,所以我有点生疏了。我认为弗拉基米尔的VALUE解决方案是一种更好的方法。


#include <stdio.h>

#if 0
extern int fact_(int n);
extern void pythagoras_(float a, float b, float *c);
#else
extern int fact_(int *n);
extern void pythagoras_(float *a, float *b, float *c);
#endif

int
main(void)
{
    float c;
#if 0
    printf("Factorial of 7 is: %d\n", fact_(7));
#else
    int n = 7;
    printf("Factorial of 7 is: %d\n", fact_(&n));
#endif

#if 0
    pythagoras_(30, 40, &c);
#else
    float a = 30;
    float b = 40;
    pythagoras_(&a, &b, &c);
#endif
    printf("Hypotenuse if sides 30, 40 is: %f\n", c);

    return 0;
}

    INTEGER*4 FUNCTION Fact (n)
    INTEGER*4 n
    INTEGER*4 i, amt
    amt = 1
    DO i = 1, n
        amt = amt * i
    END DO
    Fact = amt
    END

    SUBROUTINE Pythagoras (a, b, c)
    REAL*4 a
    REAL*4 b
    REAL*4 c
    c = SQRT (a * a + b * b)
    END

这是程序输出:

Factorial of 7 is: 5040
Hypotenuse if sides 30, 40 is: 50.000000

更新:

我从你的代码中得到了同样的undefined reference错误!

啊哈!

我没有提到的一件事[因为我认为这不会有所不同]是我将源文件名更改为使用所有小写字母(例如CMAIN.C --> cmain.cFORSUBS.FOR --> forsubs.for

这样,产生的输出nm *.o

 cmain.o:
                 U fact_
0000000000000000 T main
                 U printf
                 U pythagoras_

forsubs.o:
0000000000000000 T fact_
0000000000000045 T pythagoras_

fortran 源文件名的更改并不重要。但是,C 源文件名可以!

更重要的是它的文件名后缀(即.C更改为.c)。

这是因为gcc将 [尝试变得聪明并] 查看后缀以确定文件是用哪种语言编写的并相应地编译。例如,gcc -c foo.cpp将编译文件,就好像它是写在c++不是 c,就像命令是:g++ -c foo.cpp

虽然.cpp是文件名的 [更多] 常用后缀,但c++文件的备用后缀c++是:.C

也就是说,大多数项目都使用.cpp约定,但有些项目使用.C约定。.cpp首选的原因之一.C是 Windows 文件系统不区分大小写。所以,.C并且.c看起来是一样的。但是,POSIX 系统(例如 linux、macOSX、iOS、android 等)具有区分大小写的文件名,因此可以使用任何一种约定。

因此,gcc -c CMAIN.C将编译为c++. 这确实c++对符号进行了“名称修改”——这不是我们想要的。在c++中,修改是为了允许函数名称的“重载”。也就是说,两个 [或更多] 不同的函数可以具有相同的名称,只要它们使用不同的参数即可。例如:

void calc(int val);
void calc(int val1,int val2);
void calc(double fval);

这是nm *.o如果我们使用的输出CMAIN.C

 CMAIN.o:
0000000000000000 T main
                 U printf
                 U _Z11pythagoras_PfS_S_
                 U _Z5fact_Pi

FORSUBS.o:
0000000000000000 T fact_
0000000000000045 T pythagoras_

运行文件c++filt以“分解”c++我们得到的名称:

 CMAIN.o:
0000000000000000 T main
                 U printf
                 U pythagoras_(float*, float*, float*)
                 U fact_(int*)

FORSUBS.o:
0000000000000000 T fact_
0000000000000045 T pythagoras_

因此,如果可能,请尝试使用小写文件名 [这是推荐的最佳实践]。但是,至少不要使用.C

于 2018-12-02T23:58:00.563 回答