Фортран запрос и распечатка имя функции или подпрограммы - PullRequest
9 голосов
/ 12 августа 2011

Возможно ли в Фортране запросить имя функции или подпрограммы, в которой я нахожусь? То есть, что я ставлю вместо «???» заставить его напечатать «my_subroutine» на экране?

subroutine my_subroutine()
   write(*,*) ???
end subroutine my_subroutine

Я пытаюсь найти способ реализовать пользовательский отладчик / профилировщик, используя только механизм поиска и замены текстового редактора. Было бы полезно программно запросить мою позицию в коде.

Ответы [ 5 ]

10 голосов
/ 12 августа 2011

Нет, вы не можете. То, чего вы хотите достичь, называется отражение , и оно не доступно ни в Фортране (ни в C или C ++, если это важно).

7 голосов
/ 12 августа 2011

Вы можете использовать препроцессор для распечатки имени файла и номера строки.Возможно, вы захотите воспользоваться предопределенными символами препроцессора __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...") кажется странным синтаксисом для кода на фортране, но его заменяет препроцессор 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!

Это может иметь эффект, который вы ищете, особенно если вы пишете только одну подпрограмму на файл.

3 голосов
/ 27 сентября 2013

Я нашел простой полуавтоматический выход из этой ситуации: используйте regex, чтобы добавить жестко закодированное определение __FUNCTION__ сразу после объявления SUBROUTINE.Выполнение из make-файла позаботится о том, чтобы каждая компиляция обновляла макрос __FUNCTION__.

Предположим, у нас есть список F77, который выглядит следующим образом:

file 'my-file.F'

  SUBROUTINE my_sub(var1, var2, var3)
  INCLUDE 'some-include.PRM'
  INTEGER var1
  INTEGER var2

  ! the rest of my code here
  WRITE(*,*)__FUNCTION__

  END SUBROUTINE

Я хочу преобразовать его в

файл 'my_file.F.F'

  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

Обратите внимание, что исправленный код теперь находится в другом источникеfile: 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 $@

Предполагая, что FC определен как исполняемый файл компилятора fortran, он должен выполнить следующую процедуру на всехПодпрограммы в файле:

  • отменяют определение макроса __FUNCTION__, который, возможно, был определен ранее.
  • Добавьте директиву __FUNCTION__ на две строки ниже определения SUBROUTINE, содержащего имя подпрограммы.
  • сохранить файл под другим именем.
  • скомпилировать новый источник в требуемый объектный файл.

В этом случае результат должен быть my-file.o.

Возможно, вы заметилиЯ также использую макрос _S ().Это макрос 'stringify'.Вам просто нужно добавить его в начало вашего файла fortran (я помещаю его в config.h, который я включаю везде)

Существует другая реализация для GNU и intel:

#ifdef __INTEL_COMPILER
#define _S(x) #x
#else
#define _S(x) "x"
#endif 
2 голосов
/ 12 августа 2011

Почему бы вам просто не написать название подпрограммы, в которой вы находитесь, в операторе WRITE?

Вы не можете программно (динамически) дать или изменить имя подпрограммы, поэтому я не вижу смысла пытаться получить к нему доступ таким образом ( об этом : хотя я не уверен, что это так невозможно получить к нему какой-либо доступ, я совершенно уверен, что это неправильный путь ... вы будете причинять себе больше хлопот, чем просто жесткое кодирование).

Кстати, почему вы все равно пытаетесь его распечатать? Разве хорошо сформулированное диагностическое сообщение не будет более информативным?

1 голос
/ 17 июля 2017

Иногда в компиляторах есть нестандартные функции, которые помогут вам печатать там, где вы сейчас находитесь.Они сильно зависят от компилятора и должны использоваться только для отладки.

В gfortran вы можете использовать подпрограмму BACKTRACE .Из руководства:

BACKTRACE показывает обратную трассировку в произвольном месте в коде пользователя.После этого выполнение программы продолжается как обычно.

Вывод будет выглядеть как сообщение об ошибке, но это может быть полезно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...