使用宏的Fortran替换子例程名称

时间:2013-12-03 23:30:14

标签: macros fortran

我正在编写一个允许用户记录信息的模块。我想提供一个记录字符串消息的接口,可以将其称为

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

3 个答案:

答案 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

如果filenamelinenum附加了任何值,则内部函数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文件中,让您的用户始终包含该文件。 (类似于弗拉基米尔的回答)