问题描述
如何使用GNU gfortran将预处理器宏串化?我想将一个宏定义传递给GNU gfortran,然后将其用作代码中的字符串。
有效地,我想这样做:
程序测试
隐式无
字符(len = :),allocatable :: astring
astring = MYMACRO
写(*,*)astring
结束程序测试
然后构建与:
gfortran -DMYMACRO = hello test.F90
我试着创建各种宏,例如:
#define STRINGIFY_( x)#x
#define STRINGIFY(x)STRINGIFY_(x)
...
astring = STRINGIFY(MYMACRO)
但这不适用于gfortran预处理器。
我也尝试使用不同样式的宏:
#define STRINGIFY(x)x
...
astring = STRINGIFY(MYMACRO)
但这只是创建一个包含tex的字符串t'MYMACRO'。
然后我试着改变宏定义为:
-DMYMACRO = \hello\
但是这造成了构建中无关的问题过程。
感谢您的帮助
使用C预处理器着名的字符串化配方
viz:
pre $ STRINGIFY_(x)#x
#define STRINGIFY(x)STRINGIFY_(x)
失败的原因有两个,首先也是最简单的,你尝试使用它的源文件显然是
,它的扩展名是 .f90 code>。这个扩展对 gfortran (以及
GCC编译器驱动程序,以任何其他名称)的含义是:自由格式的Fortran源代码不应该是预处理。
同样 .f95 , .f03 和。 F08 。如果您希望 gfortran 推断源
文件包含要对必须进行预处理的免费表单Fortran代码,请为其指定一个
扩展 .F90 , .F95 , .F03 或 .F08 。请参阅
即使你做了那么简单的事情,但是,第二个原因是叮咬。
使用C预处理器预处理Fortran源文件的历史早于C
(尽管这些文件虽旧,但比Fortran年轻得多)。 gfortran 有义不是
来打破古代工作代码;因此,当它调用C预处理器时,
会以传统模式调用它。 C预处理程序
的传统模式是预处理程序在C语言(1989)的第一个标准化
之前的行为方式,因为非标准化行为可以是固定下来。在传统的
模式下,预处理器无法识别字符串化运算符'#',它是第一个C标准引入的
。您可以直接调用预处理程序
来验证这一点:
cpp -traditional test.c
其中 test.c 包含尝试使用字符串化配方的一些尝试。
的尝试失败。
您不能自行哄骗 gfortran 来处理字符串化配方。
但有一个解决方法。您可以直接调用 cpp ,不受传统模式的阻碍
预处理要完成字符串化的Fortran源并将其
输出中继到 gfortran 。如果您已经知道并且正在寻找 gfortran - 单独
解决方案,您需要阅读更多信息。
cpp -std = c89'-DSTRINGIFY_(x) =#x''-DSTRINGIFY(x)= STRINGIFY_(x)''-DMYMACRO = STRINGIFY(hello)'test.f90
输出:
#1test.f90
#1 <内置> 中
#1< command-line>
#1/usr/include/stdc-predef.h1 3 4
#1< command-line> 2
#1test.f90
程序测试
隐式无
字符(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 \
&&然后你会发现 ./test 存在并执行它会输出 hello 。
中间临时文件进一步细化。您的F90源
代码将编译为F95,因为后者是前者的保守。因此,如果
使用它的 -x $ c来告诉它你的管道是什么语言,那么你可以利用
的优势,因为GCC会将源代码编译为其标准输入$ c> 语言选项。您可以用这种方式指定的
Fortran方言是 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 -
的工作原理与前面的解决方案一样,减去临时文件,并发出
的无害警告:
警告:以$ b $的形式读取文件'< stdin>' b(注意并保留最后的 - 在命令行上,这就是告诉 gfortran 到
编译标准输入。)。 -x f95 的含义带来了额外的
经济体,该经济体由 cpp 预处理,不是由编译器再次预处理
。
使用选项 -std = c89 时调用 cpp 调用注意的
解释。它具有使 cpp 符合最早的C标准的效果。
我们可以在获得
# > - 操作符,其中的字符串化配方依赖于它,但是如果用这种方法对它进行预处理,则可以使用
来破解某些 Fortran代码。
,否则 gfortran 本身不会执行 - 传统。在
您的测试程序的情况下,您可以安全地省略 -std = c89 ,允许 cpp 到在制造时将
符合默认的C标准。但如果您允许或指示
符合 -std = c99 或更高版本,则该标准将强制识别
// 作为单行注释的开始(按照C ++),包含连接运算符的Fortran任何行
将被截断为
第一次出现。
当然,如果您使用的是使用 make 或另一个构建系统来构建
代码中你想要字符串化的宏,你将有一种方法告诉
构建系统什么样的动作构成编译给定类的可编译的
文件。对于任何Fortran源文件 fsrc ,您希望使用
a字符串序言进行编译,所指定的操作将是静态的:cpp -std = c89'-DSTRINGIFY_(x)=#x''-DSTRINGIFY(x)= STRINGIFY_(x)'\
' - DMYMACRO = STRINGIFY(hello)'fsrc.f90 | gfortran -x f95 -c -o fsrc.o -
How can I stringify a preprocessor macro with GNU gfortran? I would like to pass a macro definition to GNU gfortran which will then be used as a string in the code.
Effectively I would like to do this:
program test implicit none character (len=:), allocatable :: astring astring = MYMACRO write (*, *) astring end program testand then build with:
gfortran -DMYMACRO=hello test.F90I tried creating various macro, for example:
#define STRINGIFY_(x) #x #define STRINGIFY(x) STRINGIFY_(x) ... astring = STRINGIFY(MYMACRO)but this doesn't work with the gfortran preprocessor.
I also tried using a different style of macro:
#define STRINGIFY(x) "x" ... astring = STRINGIFY(MYMACRO)but this just creates a string containing the text 'MYMACRO'.
I then tried changing the macro definition to:
-DMYMACRO=\"hello\"but this caused unrelated problem in the build process.
Thank you for your help
解决方案Your attempt to use the well-known stringification recipe of the C preprocessor,viz:
#define STRINGIFY_(x) #x #define STRINGIFY(x) STRINGIFY_(x)fails for two reasons, each sufficient by itself.
First and simplest, the source file in which you attempt to employ it apparentlyhas the extension .f90. What this extension signifies to gfortran (and tothe GCC compiler driver, by any other name) is: Free form Fortran source code that should not be preprocessed.Similarly .f95, .f03 and .f08. If you want gfortran to infer that a sourcefile contains free form Fortran code that must be preprocessed, give it one ofthe extensions .F90, .F95, .F03 or .F08. See the GCC documentation ofthese points
Even if you do that simple thing, however, the second reason bites.
The use of the C preprocessor to preprocess Fortran source is as old as C(which though old, is much younger than Fortran). gfortran is obliged notto break ancient working code; so, when it invokes the C preprocessor,it invokes it in traditional mode. The traditional mode of the C preprocessoris the way in which the preprocessor behaved prior to the first standardizationof the C language (1989), insofar as that unstandardized behaviour can be pinned down. In traditionalmode, the preprocessor does not recognize the stringizing operator '#', which wasintroduced by the first C Standard. You can verify this by invoking the preprocessordirectly like:
cpp -traditional test.cwhere test.c contains some attempt to employ the stringification recipe. Theattempt fails.
You cannot coax gfortran on its own to work the the stringification recipe.
But there is a workaround. You can invoke cpp directly, unencumbered by traditional mode,to preprocess the Fortran source in which you want the stringification done and relay itsoutput to gfortran. If you already know this and were looking for a gfortran-alonesolution you need read no further.
Doing the stringification in your test source this way would look like:
cpp -std=c89 '-DSTRINGIFY_(x)=#x' '-DSTRINGIFY(x)=STRINGIFY_(x)' '-DMYMACRO=STRINGIFY(hello)' test.f90The output of that is:
# 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 testAnd that output is what you want to to compile. You could accomplish that as well by:
cpp -std=c89 '-DSTRINGIFY_(x)=#x' '-DSTRINGIFY(x)=STRINGIFY_(x)' \ '-DMYMACRO=STRINGIFY(hello)' test.f90 > /tmp/test.f90 \ && gfortran -o test /tmp/test.f90Then you will find that ./test exists and that executing it outputs hello.
You can eliminate the intermediate temporary file with further refinement. Your F90 sourcecode will compile as F95, as the latter is conservative of the former. So you can takeadvantage of the fact that GCC will compile source piped to its standard input ifyou tell it what language you are piping, using its -x language option. TheFortran dialects that you may specify in this way are f77, f77-cpp-input, f95and f95-cpp-input, where the -cpp-input prefix denotes thatthe source is to be preprocessed and its absence denotes that it is not. Thus
cpp -std=c89 '-DSTRINGIFY_(x)=#x' '-DSTRINGIFY(x)=STRINGIFY_(x)' \ '-DMYMACRO=STRINGIFY(hello)' test.f90 | gfortran -x f95 -o test -works as well as the previous solution, minus the temporary file, and emitsthe innocuous warning:
Warning: Reading file '<stdin>' as free form(Note and retain the final - on the commandline. That is what tells gfortran tocompile the standard input.). The meaning of -x f95 brings the additionaleconomy that the source, which is preprocessed by cpp, is not preprocessedagain by the compiler.
The use of the option -std=c89 when invoking cpp calls for a cautionaryexplanation. It has the effect of making cpp conform to the earliest C Standard.That is as close to -traditional as we can get while still availing of the#-operator, on which the stringification recipe depends, But with it you embracethe possibility of breaking some Fortran code if you preprocess it this way;otherwise gfortran itself would not enforce -traditional. In the case ofyour test program, you could safely omit -std=c89, allowing cpp to conformto the default C standard when it was built. But if you permit it or direct itto conform to -std=c99 or later, then the standard will mandate recognitionof // as the beginning of a one-line comment (as per C++), by which any lineof Fortran that contains the concatenation operator will be truncated at thefirst occurrence.
Naturally, if you use are using make or another build system to build thecode in which you want the stringified macros, you will have a way of tellingthe build system what actions constitute compiling a given class of compilablefiles. For any Fortran source file fsrc you wanted to compile witha stringification preamble, the actions to specify would be in the vein:
cpp -std=c89 '-DSTRINGIFY_(x)=#x' '-DSTRINGIFY(x)=STRINGIFY_(x)' \ '-DMYMACRO=STRINGIFY(hello)' fsrc.f90 | gfortran -x f95 -c -o fsrc.o -
这篇关于使用GNU gfortran将宏进行字符串化的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!