我正在编写一个允许用户记录信息的模块。我想提供一个记录字符串消息的接口,可以将其称为
call m_log(msg)
所以在文件m_logger.f90中,我会有
module m_logger
..
subroutine m_log(msg)
..
end module
在文件main.f90中,用户将拥有
program main
use m_logger
call m_log(msg)
end program
现在我如何用call m_log(msg)
替换call m_log(msg, __FILE__, __LINE__)
?
由于这种替换,将调用记录器模块中的不同子例程subroutine m_log(msg, filename, linenum)
。
如果我使用像#define m_log(msg) m_log(msg,__FILE__,__LINE__)
这样的宏,则必须将其添加到使用记录器的每个用户文件中。
另外,我不想强制用户明确传递__FILE__
和__LINE__
。
有没有办法可以做到这一点?或者还有其他选择吗?
提前致谢
编辑: 我讨论了comp.lang.fortran。添加链接以供参考。 here
答案 0 :(得分:3)
如果您不想明确强制__file__
和__line__
,那么您可以使用optional标记,以便您的子例程看起来像:
subroutine m_log(msg, filename, linenum)
character(len=*) :: msg
character(len=*), optional :: filename
integer, optional :: linenum
if(present(filename)) then
<something with filename>
endif
if(present(linenum)) then
<something with linenume>
endif
<normal stuff with msg>
end subroutine
如果filename
或linenum
附加了任何值,则内部函数present会返回一个真值,否则返回false。
答案 1 :(得分:3)
在这种情况下,您必须使用C使用的相同方法。定义您建议的宏
#define log(msg) m_log(msg,__FILE__,__LINE__)
在一个单独的文件中(可能包含其他有用的宏)并使用#include "file.inc"
包含它(标准的Fortran包含就不够了)。
如果宏的名称与实际调用的子例程不同,则可以确保用户必须使用include,并且不能忘记它。
答案 2 :(得分:0)
由于您希望用户将它们作为编译器宏传递,因此您首先必须为宏选择不同的名称。 __FILE__
和__LINE__
都是预定义的宏。这两个宏由预处理器定义,不由用户传递。我认为这可能会造成一些混乱。
如果您希望允许用户通过编译器选项有选择地提供宏,最好在子例程中包含#ifdef
指令:
subroutine m_log(msg)
implicit none
character(len=*) :: msg
character(len=something) :: file
integer ::line
!Initialize file and line to some default value
file=...
line=...
#ifdef __KVM_FILE__
file=__KVM_FILE__
#endif
#ifdef __KVM_LINE__
line=__KVM_LINE__
#endif
...
这样用户将始终使用相同的语法call m_log(something)
调用子例程,但效果将根据编译宏而改变。当然,这也需要用户每次更改此宏时重新编译代码。如果这样做成本太高,你可以设置一个带有可选参数的子程序(如Kyle的答案),然后在#define
块中包含#ifdef
宏,并将它们放入.h文件中,让您的用户始终包含该文件。 (类似于弗拉基米尔的回答)