stop和error stop都可以结束整个程序,但表达的含义不同:stop表示程序正常结束,error stop表示程序因为错误状态无法继续完成任务。
本篇用除法演示两条路径:除数合法时计算商并执行stop 0;除数为0或过于接近0时执行error stop。程序不使用交互输入,通过参数开关控制路径切换。
本文代码
! stop表示正常停止,error stop表示错误停止。
program stopErrorStopDemo
implicit none
real :: dividend
real :: divisor
real :: quotient
logical, parameter :: forceError = .false.
dividend = 10.0
if (forceError) then
divisor = 0.0
else
divisor = 2.0
end if
write (*,"(A,F6.2,A,F6.2)") "准备计算:", dividend, " / ", divisor
if (abs(divisor) <= epsilon(divisor)) then
error stop "除数为0或过于接近0"
end if
quotient = dividend / divisor
write (*,"(A,F6.2)") "计算结果:", quotient
write (*,"(A)") "除数合法,程序以正常状态结束。"
stop 0
end program stopErrorStopDemo
正常结束路径
(base) hong@hongdeMacBook-Pro 029.stopErrorStop % gfortran -Wall -Wextra -std=f2018 exampleStopErrorStop.f90
(base) hong@hongdeMacBook-Pro 029.stopErrorStop % ./a.out
准备计算: 10.00 / 2.00
计算结果: 5.00
除数合法,程序以正常状态结束。
STOP 0
(base) hong@hongdeMacBook-Pro 029.stopErrorStop % echo $?
0
forceError是逻辑常量,当前值为.false.。所以在divisor在if分支中被设为2.0。除法成功后,stop 0结束程序;Shell中的$?为0,表示上个命令正常完成。
错误结束路径
把代码中的forceError = .false.改为forceError = .true.后重新编译,程序会把除数设为0:
(base) hong@hongdeMacBook-Pro 029.stopErrorStop % gfortran -Wall -Wextra -std=f2018 exampleStopErrorStop.f90
(base) hong@hongdeMacBook-Pro 029.stopErrorStop % ./a.out
准备计算: 10.00 / 0.00
ERROR STOP 除数为0或过于接近0
Error termination. Backtrace:
#0 0x100c62103
#1 0x100c62cd7
#2 0x100c63f13
#3 0x1007d0743
#4 0x1007d085f
(base) hong@hongdeMacBook-Pro 029.stopErrorStop % echo $?
1
执行error stop后,后面的除法和正常结束信息都不会执行。Shell返回非零状态,这对于脚本、批处理任务和自动化测试很重要,日后我在“部署与发布”中展开写。
另外,不同编译器的错误文字和回溯格式存在差异,但错误终止的语义相同。
关于epsilon
条件abs(divisor) <= epsilon(divisor)同时拦截精确的0和过于接近0的除数。浮点数来自计算或文件时,接近0的值也可能产生非常大的商,因此不能只把检查理解为整数意义上的“是否等于0”。
stop应写在何处
当程序自然执行到end program时会正常结束,所以末尾的stop 0不是必需的。这里保留是为了明确演示正常退出状态;实际代码中,stop更适合放在需要提前结束程序的正常分支中。
常见错误
- 用普通stop掩盖输入或计算错误,导致脚本误以为程序成功。
- 把浮点数除数只判断为精确0,忽略了过于近似0的情况。
- 在错误已经发生后才调用error stop。更好的做法是在危险操作前验证条件。
知识点总结
- stop用于正常结束整个程序,error stop用于错误结束整个程序。
- 正常状态通常对应返回码0,错误状态通常对应非零返回码。
- epsilon可以帮助判断浮点数是否过于接近0。
- 使用终止语句前,应先明确它影响的是循环、过程还是整个程序。