Fortran Coder

查看: 147|回复: 4

[讨论] 请提这种错误是什么原因?

[复制链接]

36

帖子

12

主题

0

精华

熟手

F 币
142 元
贡献
80 点
发表于 2022-12-19 16:24:52 | 显示全部楼层 |阅读模式
先贴代码---------------
[Fortran] 纯文本查看 复制代码
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时,没有任何错误提示,编译成功。
1.PNG
后来查到按照下面设置即可。确实解决了问题,没有错误提示,编译成功。但心里有疑虑,这样的代码运行时,会不会有什么问题?高手能否指点下?
20210621100146738.png



1820

帖子

12

主题

5

精华

论坛跑堂

臭石头雪球

F 币
760 元
贡献
305 点

美女勋章热心勋章星光勋章新人勋章贡献勋章管理勋章帅哥勋章爱心勋章规矩勋章元老勋章水王勋章

发表于 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. 没有多大意义。

36

帖子

12

主题

0

精华

熟手

F 币
142 元
贡献
80 点
 楼主| 发表于 2022-12-19 18:37:06 | 显示全部楼层
非常感谢您,终于明白我的错在哪里了,非常感谢。
要是声明这个数组时,按照正常语法,直接声明其大小,就没有这种错误提示了。另外,我试了试,上面的代码虽然编译成功,但是输出结果仍然是原始值(1,2,3,4,5)。说明子程序没有起作用。再次感谢

1820

帖子

12

主题

5

精华

论坛跑堂

臭石头雪球

F 币
760 元
贡献
305 点

美女勋章热心勋章星光勋章新人勋章贡献勋章管理勋章帅哥勋章爱心勋章规矩勋章元老勋章水王勋章

发表于 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的一种猜测。


36

帖子

12

主题

0

精华

熟手

F 币
142 元
贡献
80 点
 楼主| 发表于 2022-12-20 16:39:34 | 显示全部楼层
佩服。有道理。确认了解决这个问题就是两种方法:
(1)采用 integer  :: num1(:)  这样的声明方式,然后把subroutine封装module。这也也省事,就是不需要把子程序中每个数组的维度都传递进去。
(2)采用 integer  :: num1(5) 这样的声明方式,不需要module。

您需要登录后才可以回帖 登录 | 极速注册

本版积分规则

捐赠本站|Archiver|关于我们 About Us|小黑屋|Fcode ( 京ICP备18005632-2号 )

GMT+8, 2023-2-4 18:02

Powered by Tencent X3.4

© 2013-2023 Tencent

快速回复 返回顶部 返回列表