Ваша попытка использовать хорошо известный рецепт стробирования препроцессора C, а именно:
#define STRINGIFY_(x) #x
#define STRINGIFY(x) STRINGIFY_(x)
терпит неудачу по двум причинам, каждая из которых достаточна сама по себе.
Первое и самое простое: исходный файл, в котором вы пытаетесь его использовать, очевидно, имеет расширение .f90
. Что это расширение означает для gfortran
(и для драйвера компилятора GCC под любым другим именем): Исходный код свободной формы Fortran, который не должен подвергаться предварительной обработке. Аналогично .f95
, .f03
и .f08
. Если вы хотите, чтобы gfortran
выводил, что исходный файл содержит код Fortran в свободной форме, который должен быть предварительно обработан, присвойте ему одно из расширений .F90
, .F95
, .F03
или .F08
. См. документацию GCC по этим точкам.
Однако, даже если вы делаете эту простую вещь, вторая причина кусается.
Использование препроцессора C для предварительной обработки исходного кода Fortran так же старо, как C (который хотя и стар, но намного моложе, чем Fortran). gfortran
обязуется не нарушать древний рабочий код; поэтому, когда он вызывает препроцессор C, он вызывает его в традиционном режиме. Традиционный режим препроцессора C — это то, как препроцессор вел себя до первой стандартизации языка C (1989 г.), поскольку это нестандартное поведение может быть зафиксировано. В традиционном режиме препроцессор не распознает строковый оператор '#', который был введен в первом стандарте C. Вы можете проверить это, вызвав препроцессор напрямую, например:
cpp -traditional test.c
где test.c
содержит некоторую попытку использовать рецепт стрингификации. Попытка не удалась.
Вы не можете уговорить gfortran
самостоятельно работать по рецепту стрингификации.
Но есть обходной путь. Вы можете вызвать cpp
напрямую, не обремененный традиционным режимом, для предварительной обработки исходного кода на Фортране, в котором вы хотите выполнить строковое преобразование, и передать его вывод в gfortran
. Если вы уже знаете это и ищете gfortran
-одиночное решение, вам не нужно читать дальше.
Выполнение стробирования в вашем тестовом источнике таким образом будет выглядеть так:
cpp -std=c89 '-DSTRINGIFY_(x)=#x' '-DSTRINGIFY(x)=STRINGIFY_(x)' '-DMYMACRO=STRINGIFY(hello)' test.f90
Результат этого:
# 1 "test.f90"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "/usr/include/stdc-predef.h" 1 3 4
# 1 "<command-line>" 2
# 1 "test.f90"
program test
implicit none
character (len=:), allocatable :: astring
astring = "hello"
write (*, *) astring
end program test
И этот вывод - это то, что вы хотите скомпилировать. Вы также можете сделать это:
cpp -std=c89 '-DSTRINGIFY_(x)=#x' '-DSTRINGIFY(x)=STRINGIFY_(x)' \
'-DMYMACRO=STRINGIFY(hello)' test.f90 > /tmp/test.f90 \
&& gfortran -o test /tmp/test.f90
Затем вы обнаружите, что ./test
существует и что его выполнение выводит hello
.
Вы можете удалить промежуточный временный файл с дальнейшей доработкой. Ваш исходный код F90 будет скомпилирован как F95, поскольку последний является консервативным по отношению к первому. Таким образом, вы можете воспользоваться тем фактом, что GCC будет компилировать исходный код, передаваемый на его стандартный ввод, если вы укажете ему, какой язык вы передаете, используя параметр -x
language. Диалекты Фортрана, которые вы можете указать таким образом, это f77
, f77-cpp-input
, f95
и f95-cpp-input
, где префикс -cpp-input
означает, что исходный код должен быть предварительно обработан, а его отсутствие означает, что это не так. Таким образом
cpp -std=c89 '-DSTRINGIFY_(x)=#x' '-DSTRINGIFY(x)=STRINGIFY_(x)' \
'-DMYMACRO=STRINGIFY(hello)' test.f90 | gfortran -x f95 -o test -
работает так же, как и предыдущее решение, за исключением временного файла, и выдает безобидное предупреждение:
Warning: Reading file '<stdin>' as free form
(Обратите внимание и сохраните последний -
в командной строке. Это то, что говорит gfortran
скомпилировать стандартный ввод.). Значение -x f95
приносит дополнительную экономию, поскольку исходный код, предварительно обработанный cpp
, не подвергается повторной предварительной обработке компилятором.
Использование опции -std=c89
при вызове cpp
требует осторожного объяснения. Это приводит к тому, что cpp
соответствует самому раннему стандарту C. Это максимально близко к -traditional
, насколько мы можем получить, все еще используя #
-оператор, от которого зависит рецепт строковой обработки. способ; в противном случае сам gfortran
не будет применять -traditional
. В случае с вашей тестовой программой вы можете безопасно опустить -std=c89
, что позволит cpp
соответствовать стандарту C по умолчанию, когда он был построен. Но если вы разрешите или укажете, чтобы он соответствовал -std=c99
или более поздней версии, то стандарт предписывает распознавать //
как начало однострочного комментария (согласно C++), благодаря чему любая строка Фортрана, содержащая оператор конкатенации, будет быть усеченным при первом появлении.
Естественно, если вы используете make
или другую систему сборки для сборки кода, в котором вам нужны строковые макросы, у вас будет способ сообщить системе сборки, какие действия составляют компиляцию данного класса компилируемых файлы. Для любого исходного файла Fortran fsrc
, который вы хотите скомпилировать с преамбулой строковой модификации, действия, которые необходимо указать, будут примерно такими:
cpp -std=c89 '-DSTRINGIFY_(x)=#x' '-DSTRINGIFY(x)=STRINGIFY_(x)' \
'-DMYMACRO=STRINGIFY(hello)' fsrc.f90 | gfortran -x f95 -c -o fsrc.o -
person
Mike Kinghan
schedule
31.07.2015
-DMYMACRO=\"hello\"
правильный подход. Какие проблемы это вызвало? - person Vladimir F   schedule 27.07.2015#define STRINGIFY(x) "x"
. Я обнаружил, что он только что создал строку, содержащую текст «MYMACRO». - person Jim Eliot   schedule 28.07.2015