-
Notifications
You must be signed in to change notification settings - Fork 9
/
cpp.tex
227 lines (213 loc) · 7.89 KB
/
cpp.tex
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
\section{The C preprocessor}
\label{Cpp}
The C preprocessor, \code{cpp}, is a standalone program which comes
with most C compilers. On older UNIX systems it was not in the default
path, but in \code{/lib} or in \code{/usr/lib}. Most modern systems
have some version of \code{gcc} which comes with a quite capable
\code{cpp}. Just be sure to give it the \code{-traditional} flag.
This Appendix describes the C preprocessor as used in ROMS with the
Fortran language. A more complete description is given by
\citet{K&R}. More practical advice on using
\code{cpp} is given by \citet{Hazard}.
\subsection{File inclusion}
Placing common blocks in smaller files, which are then included in each
subroutine, is the easiest way to make sure that the common blocks are
declared consistently. Many Fortran compilers support an include
statement where the compiler replaces the line
\begin{verbatim}
include 'file.h'
\end{verbatim}
with the contents of \code{file.h}; \code{file.h} is assumed
to be in the current directory. The C preprocessor has an equivalent
include statement:
\begin{verbatim}
#include "file.h"
\end{verbatim}
We are using the C preprocessor style of include because many of the
ROMS include files are not pure Fortran and must be processed by
\code{cpp}.
\subsection{Macro substitution}
A macro definition has the form
\begin{verbatim}
#define name replacement text
\end{verbatim}
where ``name'' would be replaced with ``replacement text''
throughout the rest of the file. This was used in SCRUM as a
reasonably portable way to get 64-bit precision:
\begin{verbatim}
#define BIGREAL real*8
\end{verbatim}
It is customary to use uppercase for \code{cpp} macros---the C
preprocessor is case sensitive.
It is also possible to define macros with arguments, as in
\begin{verbatim}
#define av2(a1,a2) (.5 * ((a1) + (a2)))
\end{verbatim}
although this is riskier than the equivalent statement function
\begin{verbatim}
av2(a1,a2) = .5 * (a1 + a2)
\end{verbatim}
The statement function is preferable because it allows the compiler
to do type checking and because you don't have to be as careful
about using enough parentheses.
The third form of macro has no replacement text at all:
\begin{verbatim}
#define MASKING
\end{verbatim}
In this case, \code{MASKING} will evaluate to \code{true} in the
conditional tests described below.
\subsection{Conditional inclusion}
It is possible to control which parts of the code are seen by the
Fortran compiler by the use of \code{cpp}'s conditional inclusion.
For example, the statements
\begin{verbatim}
#ifdef MASKING
# include "mask.h"
#endif /* MASKING */
:
# ifdef MASKING
c
c Apply Land/Sea mask: slipperiness.
c
do j=1,M
do i=2,Lm
Uflux(i,j)=Uflux(i,j)*pmask(i,j)
enddo
enddo
# endif /* MASKING */
\end{verbatim}
will not be in the Fortran source code if \code{MASKING} has not
been defined. Likewise,
\code{\#ifndef} tests for a macro being undefined:
\begin{verbatim}
#ifndef RMDOCINC
c rmask Mask at RHO-points (0=Land, 1=Sea).
c pmask Slipperiness mask at PSI-points (0=Land, 1=Sea,
c 1-gamma2=boundary).
c umask Mask at U-points (0=Land, 1=Sea).
c vmask Mask at V-points (0=Land, 1=Sea).
c
c=======================================================================
#endif
\end{verbatim}
There are also \code{\#else} and \code{\#elif} (else if) statements.
%although \code{\#elif} is newer and is not supported by all versions of
%\code{cpp}.
An example using \code{\#else} and \code{\#elif} is
shown:
\begin{verbatim}
#ifdef SOLITON
real(r8) :: g = 1.0_r8 ! non-dimensional
# elif defined WBC_1 || defined WBC_2 || defined WBC_3
real(r8) :: g = 9.8_r8 ! m/s2
# elif defined CIRCLE
real(r8) :: g = 3.92e-2_r8 ! m/s2
#else
real(r8) :: g = 9.81_r8 ! m/s2
#endif
\end{verbatim}
Actually, \code{\#ifdef} is a restricted version of the more general
test
\begin{verbatim}
#if expression
\end{verbatim}
where ``expression'' is a constant integer value. Zero evaluates
to \code{false} and everything else is considered \code{true}.
Compound expressions may be built using the C logical operators:
\begin{verbatim}
&& logical and
|| logical or
! logical not
\end{verbatim}
These symbols would be used as in the following example:
\begin{verbatim}
#if defined CANYON_A || defined CANYON_B
do j=0,M
do i=0,L
yc=c32000-c16000*(sin(pi*xr(i,j)/xl))**24
h(i,j)=c20+p5*(hmax-c20)*(c1+tanh((yr(i,j)-yc)/c10000))
enddo
enddo
#endif
\end{verbatim}
\subsection{C comments}
The C preprocessor will also delete C language comments starting
with \code{/*} and ending with \code{*/} as in:
\begin{verbatim}
#endif /* MASKING */
\end{verbatim}
When mixed with Fortran code, it is safer to use a Fortran
comment.
\subsection{A note on style}
In ROMS, the style adopted is as shown above and here:
\begin{verbatim}
#define NEP5
#if defined NEP5 || defined BERING
:
# ifdef MASKING
:
# endif
#endif
\end{verbatim}
The \code{gnu} community has instead adopted this style:
\begin{verbatim}
#define NEP5 1
#if NEP5 || BERING
:
# if MASKING
:
# endif
#endif
\end{verbatim}
Both styles work and you should be aware that there's more than one
way to do it.
\subsection{Potential problems}
The use of the C preprocessor is not entirely free of problems, but
many can be worked around or avoided by using the \code{gnu} version of
\code{cpp} with the \code{-traditional} flag.
\begin{enumerate}
\item Apostrophes in Fortran comments. \code{cpp} does not
know that it is in a comment and some versions will complain about
unmatched apostrophes in the following:
\begin{verbatim}
! Some useful comment about Green's functions.
\end{verbatim}
\item \CC\ comments. Some of the newer versions of
\code{cpp} will remove \CC\ comments which go from '//' to
the end of the line. Some perfectly reasonable Fortran lines
contain two consecutive slashes, such as:
\begin{verbatim}
common // var1, var2
44 format(//)
\end{verbatim}
and Fortran 90 string concatenation:
\begin{verbatim}
mystring = 'Hello, ' // 'World!'
\end{verbatim}
\item Macro replacement. One feature of \code{cpp} is that you
can define macros and have it perform replacements. The code:
\begin{verbatim}
#define REAL double precision
REAL really_long_variable, second_long_variable
\end{verbatim}
becomes
\begin{verbatim}
double precision really_long_variable, second_long_variable
\end{verbatim}
and you run the risk of creating lines which are longer than 72
characters in length.
Also, make sure that your macros will not be found anywhere else
in the code. I used to use \code{\#define DOUBLE} for double
precision until it was pointed out to me that \code{DOUBLE}
\code{PRECISION} is perfectly valid Fortran. Since a string
that is simply ``defined'' becomes 1, the macro processor would
turn this into \code{1 PRECISION}.
\end{enumerate}
\subsection{Modern Fortran}
I started working on these ocean models before 1990, much less before
Fortran 90 compilers were generally available. Fortran 90's \code{kind}
feature as used in ROMS is a better way to handle the \code{BIGREAL}
type declarations. On the other hand, Fortran 90 does not include
conditional compilation. However, it is deemed useful enough that the
Fortran 2003 standard has the coco means of conditional compilation.
We {\em might} start using this in about ten years.