静待花开 发表于 2022-12-19 16:24:52

请提这种错误是什么原因?

先贴代码---------------
program ex0816
implicit none
integer:: a(5)=(/ 1,2,3,4,5 /)
Call ShowArray1(a)
write(6,*)a
Stop
End

Subroutine ShowArray1(num1)
implicit none
integer:: num1(:)
num1 = num1 + 1
write(6,*)num1
return
End
---------------
自我感觉这个代码没有什么问题,但在IVF编译时(Debug),提示下面错误。但选择Release时,没有任何错误提示,编译成功。

后来查到按照下面设置即可。确实解决了问题,没有错误提示,编译成功。但心里有疑虑,这样的代码运行时,会不会有什么问题?高手能否指点下?




fcode 发表于 2022-12-19 17:24:37

integer :: num1(:)
这种写法属于函数的高级用法,它需要有显式的接口(interface),以便编译器能自动协调“调用者”和“被调用者”

关于 interface 你可以看书,或看李老师的教程,有详细的说明。
错误提示就是在提醒你,需要写显式接口(interface)

在这里,有几点可以说明:
1. 使用module并把函数包含在module里,可以避免手动书写接口。
现代 Fortran 代码,除了主程序,其他代码应该全部放在module里。
2. 有些编译器,可以在某些情况下,自动为你生成interface接口,这样编译器可以自动找出接口不一致的错误来。
(这属于编译器额外赠送的东西,不要过度依赖它。
3. intel fortran 在debug时会开启 Check Routine Interfaces,这是一个很好的功能,有利于编译时发现代码的问题,不建议关闭。

最后,我是个循规蹈矩的人,按语法去规范自己的代码。
我不是很愿意去琢磨“如果不按语法会发生什么”这种事情。原因是:
1. 会发生什么,语法没有规定,不同的编译器实现,可能会有不同的后果。(没有后果也是一种可能)
2. 没有多大意义。

静待花开 发表于 2022-12-19 18:37:06

非常感谢您,终于明白我的错在哪里了,非常感谢。
要是声明这个数组时,按照正常语法,直接声明其大小,就没有这种错误提示了。另外,我试了试,上面的代码虽然编译成功,但是输出结果仍然是原始值(1,2,3,4,5)。说明子程序没有起作用。再次感谢

fcode 发表于 2022-12-20 08:33:54

静待花开 发表于 2022-12-19 18:37
非常感谢您,终于明白我的错在哪里了,非常感谢。
要是声明这个数组时,按照正常语法,直接声明其大小,就 ...
子程序中把虚参直接声明成固定大小的数组,这属于基本用法(区别于假定形状这种高级用法),基本用法不需要书写interface。

为什么子程序没起作用呢?
我估计是因为:
子程序用了 integer:: num1(:) 声明虚参,是假定形状用法。
它需要调用者(主程序)除了给出 num 的数组名(首地址)外,还需要给出其数组形状(维度,大小,等)
而因为缺少interface,主程序并不知道需要这些信息,于是没有给,只给了首地址。
这样,恰巧主程序a后面的一个内存位置是个0,于是,子程序以为 num 数组的大小为0,子程序中num1 = num1 + 1 就无效。并且子程序中write也没有输出内容。

再次强调,不按语法规则编写代码,会导致什么后果,语法并未规定,每个编译器实现(甚至同一个编译器,某些选项开启或关闭的情况下),均可能有不同的反应。
以上也只是针对intel fortran的一种猜测。


静待花开 发表于 2022-12-20 16:39:34

佩服。有道理。确认了解决这个问题就是两种方法:
(1)采用 integer:: num1(:)这样的声明方式,然后把subroutine封装module。这也也省事,就是不需要把子程序中每个数组的维度都传递进去。
(2)采用 integer:: num1(5) 这样的声明方式,不需要module。

页: [1]
查看完整版本: 请提这种错误是什么原因?