Gfortran -Wuninitialized 标志在 do 循环中缺少变量
Posted
技术标签:
【中文标题】Gfortran -Wuninitialized 标志在 do 循环中缺少变量【英文标题】:Gfortran -Wuninitialized flag misses variable in do loop 【发布时间】:2016-09-20 10:07:44 【问题描述】:考虑以下代码:
PROGRAM TEST
IMPLICIT NONE
REAL:: noninit
noninit = noninit + 1
END PROGRAM TEST
如果使用gfortran -Wall TEST.f90
编译,则会正确生成‘noninit’ is used uninitialized in this function [-Wuninitialized]
的警告。现在考虑 do 循环中的相同代码:
PROGRAM TEST
IMPLICIT NONE
REAL:: noninit
INTEGER:: ii
DO ii=1,10
noninit = noninit + 1 ! line 8
END DO
print *, "noninit = ", noninit
END PROGRAM TEST
当遵守相同的命令时,不会产生未初始化变量的警告。您能否解释为什么会发生这种行为以及我能做些什么来解决它?我当前的解决方案是使用-finit-real=snan
标志来创建一个易于跟踪的垃圾线索,以防变量未初始化。有没有更好的解决方案?
【问题讨论】:
如果你使用Linux,你可以在运行时使用valgrind。 使用valgrind --track-origins=yes ./a.out
不会发现未初始化的变量。如果我在 do 循环中包含一个 write 语句,那么 valgrind 可以找到它。这是预期的行为吗?
对不起,是的,这是意料之中的,它只在变量的使用影响程序输出时报告。
这很可能是一开始的问题,如果编译器看到循环什么都不做并跳过它,。 (当然结果也不会在第一种情况下使用)尝试在循环之后写一个 。
@VladimirF 这很奇怪 - 如果我只用两个语句尝试 OP 的程序:WRITE(*, *) noninit; noninit = noninit + 1
然后gfortran -O0 -Wall -Wextra
不会产生警告,而如果我删除 WRITE
语句,警告生成(gfortran 6.1.0)
【参考方案1】:
假定错误的特征
对于初学者来说,准确缩小这个(假定的)错误发生的时间是有帮助的,在我看来,如果这两个条件都成立,就会发生这种情况:
-
内部循环
变量同时出现在左右两侧(例如
x=x+1
)
变量是隐式声明还是显式声明,它们是整数还是实数似乎都无关紧要。
因此,虽然这似乎是一个编译器错误,但情况非常有限,-Wuninitialized
将捕获绝大多数未初始化变量的错误,即使在 do 循环内也是如此。
此外,虽然-Wuninitialized
在上述情况下会失败,但这里还有一些其他 gfortran 编译器标志可能非常有用,至少在实数方面——我不知道有什么方法可以捕获整数。请参阅下面的几个选项。
gfortran version = 5.5.0
(在linux系统上测试)
用于捕获未声明实数的选项 1
shell 命令:
> gfortran -finit-real=snan main.f90
> ./a.out
输出:
noninit = NaN
注意事项:
-
这不会给出编译器警告,也不会导致运行时错误,但它将 NONINIT 初始化为 NaN 而不是零,这更有可能提示您解决这里的问题,但显然它取决于关于您的程序稍后使用 NONINIT 究竟做了什么。
由于此选项将实数显式初始化为 NaN,因此它会否定您从
-Wuninitialized
获得的任何实数警告,因为现在不会未初始化任何实数!但是对于大多数未初始化的整数,您仍然应该收到警告。
用于捕获未声明实数的选项 2
shell 命令:
> gfortran -finit-real=snan -ffpe-trap=invalid,zero,overflow -g main.f90
> ./a.out
输出:
Program received signal SIGFPE: Floating-point exception - erroneous
arithmetic operation.
Backtrace for this error:
#0 0x7FCE45AFC697
#1 0x7FCE45AFCCDE
#2 0x7FCE44FF73EF
#3 0x400818 in MAIN__ at main.f90:8
Floating point exception
注意事项:
-ffpe-trap
的重要选项是“无效”,但我包括“零”和“溢出”只是因为似乎大多数使用此标志的人似乎都使用这三个选项。
需要-g
标志来查看导致崩溃的行号(如果没有-g
,它仍然会崩溃,但您不会知道它是哪一行)。
【讨论】:
【参考方案2】:这是特定编译器中的特定缺陷。我不确定它是否按照我们在 cmets 中的建议报告给了 GCC bugzilla。
其他编译器可以捕获它:
> ifort -g -warn -check noninit.f90
> ./a.out
forrtl: severe (194): Run-Time Check Failure. The variable 'test_$NONINIT' is being used in 'noninit.f90(7,5)' without being defined
Image PC Routine Line Source
a.out 0000000000402A2F Unknown Unknown Unknown
a.out 0000000000402992 Unknown Unknown Unknown
libc-2.26.so 00007F009F1A934A __libc_start_main Unknown Unknown
a.out 00000000004028AA Unknown Unknown Unknown
我敢打赌,拥有丰富调试功能的 NAG 也会赶上它。
【讨论】:
(请注意,这是一个 runtime 警告,与循环外的-Wuninitialized
所需的情况不同。类似的效果,虽然输出帮助不大,但可以通过 gfortran 的-finit-real=snan
,如问题中所述。)
@francescalus 确实如此,但它提供了源代码位置和一个很好的错误消息。 gfortran 的选项需要启用我不喜欢的 FP 异常,这实际上会破坏我的代码(我确实删除零然后丢弃结果,而不是通过代价高昂的 if 进行检查)。
在这种情况下,这并不是我真正想要的,但根本没有其他人回答,所以让我们认为这是对过去帮助的奖励 ;-)以上是关于Gfortran -Wuninitialized 标志在 do 循环中缺少变量的主要内容,如果未能解决你的问题,请参考以下文章
Mac OS X 10.8.3 上的 gfortran/gcc4.8
gfortran 中的 ieee_arithmetic 内在模块
不能在Ubuntu上使用gfortran和Abaqus 2016
在ubuntu上安装了gfortran编译器,出现了大问题哦!!求助啊!!