使用GNU gfortran将宏进行字符串化 [英] Stringify macro with GNU gfortran

查看:208
本文介绍了使用GNU gfortran将宏进行字符串化的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如何使用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 。请参阅这些点的
的GCC文档



即使你做了那么简单的事情,但是,第二个原因是叮咬。



使用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 的优势,因为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 test

and then build with:

gfortran -DMYMACRO=hello test.F90

I 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 apparently has the extension .f90. What this extension signifies to gfortran (and to the 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 source file contains free form Fortran code that must be preprocessed, give it one of the extensions .F90, .F95, .F03 or .F08. See the GCC documentation of these 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 not to break ancient working code; so, when it invokes the C preprocessor, it invokes it in traditional mode. The traditional mode of the C preprocessor is the way in which the preprocessor behaved prior to the first standardization of the C language (1989), insofar as that unstandardized behaviour can be pinned down. In traditional mode, the preprocessor does not recognize the stringizing operator '#', which was introduced by the first C Standard. You can verify this by invoking the preprocessor directly like:

cpp -traditional test.c

where test.c contains some attempt to employ the stringification recipe. The attempt 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 its output to gfortran. If you already know this and were looking for a gfortran-alone solution 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.f90

The 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 test

And 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.f90

Then you will find that ./test exists and that executing it outputs hello.

You can eliminate the intermediate temporary file with further refinement. Your F90 source code will compile as F95, as the latter is conservative of the former. So you can take advantage of the fact that GCC will compile source piped to its standard input if you tell it what language you are piping, using its -x language option. The Fortran dialects that you may specify in this way are f77, f77-cpp-input, f95 and f95-cpp-input, where the -cpp-input prefix denotes that the 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 emits the innocuous warning:

Warning: Reading file '<stdin>' as free form

(Note and retain the final - on the commandline. That is what tells gfortran to compile the standard input.). The meaning of -x f95 brings the additional economy that the source, which is preprocessed by cpp, is not preprocessed again by the compiler.

The use of the option -std=c89 when invoking cpp calls for a cautionary explanation. 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 embrace the possibility of breaking some Fortran code if you preprocess it this way; otherwise gfortran itself would not enforce -traditional. In the case of your test program, you could safely omit -std=c89, allowing cpp to conform to the default C standard when it was built. But if you permit it or direct it to conform to -std=c99 or later, then the standard will mandate recognition of // as the beginning of a one-line comment (as per C++), by which any line of Fortran that contains the concatenation operator will be truncated at the first occurrence.

Naturally, if you use are using make or another build system to build the code in which you want the stringified macros, you will have a way of telling the build system what actions constitute compiling a given class of compilable files. For any Fortran source file fsrc you wanted to compile with a 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将宏进行字符串化的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆