在Fortran中,是否可以查询当前所在函数或子程序的名称?即,在代码中替换 '???' 可以打印出屏幕上的'my_subroutine'。
subroutine my_subroutine()
write(*,*) ???
end subroutine my_subroutine
我正在尝试使用文本编辑器的搜索和替换机制实现自定义调试器/分析器。编程查询我的代码位置将会很有帮助。
在Fortran中,是否可以查询当前所在函数或子程序的名称?即,在代码中替换 '???' 可以打印出屏幕上的'my_subroutine'。
subroutine my_subroutine()
write(*,*) ???
end subroutine my_subroutine
我正在尝试使用文本编辑器的搜索和替换机制实现自定义调试器/分析器。编程查询我的代码位置将会很有帮助。
你可以使用预处理器来打印文件名和行号。你可能想要利用预定义的预处理器符号__LINE__
和__FILE__
。以下是一个示例:
在头文件中定义预处理宏(以便在多个位置使用),称之为errormsg.h:
#define ERRORMSG(msg) write(0,'("There was an error at ",I4," in file ",/,A,/,"Error message: ",A)') __LINE__,__FILE__,msg
然后,您可以将此头文件包含在程序、库或模块文件中,例如:
#include "errormsg.h"
program main
ERRORMSG("not really an error...")
call foo()
end program
subroutine foo()
ERRORMSG("not an error too!")
end subroutine
ERRORMSG("not really an error...")
看起来像是Fortran代码中的奇怪语法,但它会使用宏定义被C预处理器替换。因此,编译时它看起来是这样:
write(0,'("There was an error at ",I4," in file ",/,A,/,"Error message: ",A)') __LINE__,__FILE__,"not really an error"
对于我的ERRORMSG
宏,我选择使用0文件单元来将其打印到stderr。显然,您可以自由地编写消息,只要它能产生符合语法的FORTRAN代码即可。
要使其编译通过,您需要向编译器传递标志,而这些标志在不同的编译器上略有不同。例如,以下方法适用于我:
gfortran -cpp -o errorTest errorTest.f90
也就是说,对于gfortran来说,-cpp
在编译之前调用了C预处理器。 上述程序的输出如下:
There was an error at 5 in file
errorTest.f90
Error message: not really an error...
There was an error at 13 in file
errorTest.f90
Error message: not an error too!
这可能会产生您所期望的效果,特别是如果您每个文件只编写一个子程序。
SUBROUTINE my_sub(var1, var2, var3)
INCLUDE 'some-include.PRM'
INTEGER var1
INTEGER var2
! the rest of my code here
WRITE(*,*)__FUNCTION__
END SUBROUTINE
SUBROUTINE my_sub(var1, var2, var3)
#undef __FUNCTION__
#define __FUNCTION__ "my_sub"
INCLUDE 'some-include.PRM'
INTEGER var1
INTEGER var2
! the rest of my code here
WRITE(*,*)__FUNCTION__
END SUBROUTINE
my-file.F.F
为了做到这一点,我向“Makefile”添加了以下行:my-file.o: my-file.F
perl -pne 's/^(\s+SUBROUTINE\s*)([^(]+)(\(.*\))/$$1$$2$$3\n#undef __FUNCTION__\n#define __FUNCTION__ _S($$2)/ixms' $< > $<.F; \
$(FC) $(CPPFLAGS) $(FCFLAGS) -c $<.F -o $@
my-file.o
。#ifdef __INTEL_COMPILER
#define _S(x) #x
#else
#define _S(x) "x"
#endif
有时编译器会有非标准功能,帮助你打印当前所在位置。这些高度特定于编译器,并且只应用于调试。
在gfortran中,您可以使用子程序BACKTRACE。来自手册:
BACKTRACE显示用户代码中任意位置的回溯。程序继续正常执行。
输出看起来像错误消息,但可能有所帮助。