我正在尝试将this code(gist as back up)修改为与gfortran-gcc兼容。
[VALUE]
标签POINTER
标志的-fcray-pointer
用于gfortran,而不是[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 *)'的未定义引用
如果您能帮助我知道,我将不胜感激:
P.S.1。也已在Reddit上共享。 P.S.2。操作系统和编译器规范与this question相同。
答案 0 :(得分:4)
Fortran通过引用传递变量,正如任何Fortran to C教程的第一句话所述。所以你:
不能只删除[VALUE]
,您应该添加现代的VALUE属性或更改C代码以传递指针。
不应在[REFERENCE]
的Fortran端使用指针,而应将其删除。
这些天通常为编译器使用实际的名称处理,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语言中看到的所有C临时变量。其他答案。 bind(C)
是VALUE
正常工作所必需的。这样可以避免您重写调用Fortran过程的代码。
为获得最佳现代体验,请使用bind(C,name="any_name_you_want")
来设置确切的链接符号名称。
答案 1 :(得分:4)
除了我的主要评论外,Fortran还通过引用传递,因此您必须修改.c
和.for
文件。
以下代码有效。可能有一种更简单的声明方式,但这(至少)应该使您更进一步。 注意事项:自从Fortran IV以来,我并没有做太多的fortran,所以我有点生锈。我将弗拉基米尔(Vladimir)的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.c
和FORSUBS.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++
编写的,而 not 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