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编译器,出现了大问题哦!!求助啊!!

编译 RcppArmadillo 时遇到问题 - 未找到库 gfortran

对“_gfortran_transfer_character_write”的未定义引用