Extensions implemented in GNU Fortran#
GNU Fortran implements a number of extensions over standard Fortran.
This chapter contains information on their syntax and meaning. There
are currently two categories of GNU Fortran extensions, those that
provide functionality beyond that provided by any standard, and those
that are supported by GNU Fortran purely for backward compatibility
with legacy compilers. By default, -std=gnu
allows the
compiler to accept both types of extensions, but to warn about the use
of the latter. Specifying either -std=f95
,
-std=f2003
, -std=f2008
, or -std=f2018
disables both types of extensions, and -std=legacy
allows
both without warning. The special compile flag -fdec
enables
additional compatibility extensions along with those enabled by
-std=legacy
.
Old-style kind specifications#
GNU Fortran allows old-style kind specifications in declarations. These look like:
TYPESPEC*size x,y,z
where TYPESPEC
is a basic type (INTEGER
, REAL
,
etc.), and where size
is a byte count corresponding to the
storage size of a valid kind for that type. (For COMPLEX
variables, size
is the total size of the real and imaginary
parts.) The statement then declares x
, y
and z
to
be of type TYPESPEC
with the appropriate kind. This is
equivalent to the standard-conforming declaration
TYPESPEC(k) x,y,z
where k
is the kind parameter suitable for the intended precision. As
kind parameters are implementation-dependent, use the KIND
,
SELECTED_INT_KIND
and SELECTED_REAL_KIND
intrinsics to retrieve
the correct value, for instance REAL*8 x
can be replaced by:
INTEGER, PARAMETER :: dbl = KIND(1.0d0)
REAL(KIND=dbl) :: x
Old-style variable initialization#
GNU Fortran allows old-style initialization of variables of the form:
INTEGER i/1/,j/2/
REAL x(2,2) /3*0.,1./
The syntax for the initializers is as for the DATA
statement, but
unlike in a DATA
statement, an initializer only applies to the
variable immediately preceding the initialization. In other words,
something like INTEGER I,J/2,3/
is not valid. This style of
initialization is only allowed in declarations without double colons
(::
); the double colons were introduced in Fortran 90, which also
introduced a standard syntax for initializing variables in type
declarations.
Examples of standard-conforming code equivalent to the above example are:
! Fortran 90
INTEGER :: i = 1, j = 2
REAL :: x(2,2) = RESHAPE((/0.,0.,0.,1./),SHAPE(x))
! Fortran 77
INTEGER i, j
REAL x(2,2)
DATA i/1/, j/2/, x/3*0.,1./
Note that variables which are explicitly initialized in declarations
or in DATA
statements automatically acquire the SAVE
attribute.
Extensions to namelist#
GNU Fortran fully supports the Fortran 95 standard for namelist I/O including array qualifiers, substrings and fully qualified derived types. The output from a namelist write is compatible with namelist read. The output has all names in upper case and indentation to column 1 after the namelist name. Two extensions are permitted:
Old-style use of $
instead of &
$MYNML
X(:)%Y(2) = 1.0 2.0 3.0
CH(1:4) = "abcd"
$END
It should be noted that the default terminator is /
rather than
&END
.
Querying of the namelist when inputting from stdin. After at least
one space, entering ?
sends to stdout the namelist name and the names of
the variables in the namelist:
?
&mynml
x
x%y
ch
&end
Entering =?
outputs the namelist to stdout, as if
WRITE(*,NML = mynml)
had been called:
=?
&MYNML
X(1)%Y= 0.000000 , 1.000000 , 0.000000 ,
X(2)%Y= 0.000000 , 2.000000 , 0.000000 ,
X(3)%Y= 0.000000 , 3.000000 , 0.000000 ,
CH=abcd, /
To aid this dialog, when input is from stdin, errors send their
messages to stderr and execution continues, even if IOSTAT
is set.
PRINT
namelist is permitted. This causes an error if
-std=f95
is used.
PROGRAM test_print
REAL, dimension (4) :: x = (/1.0, 2.0, 3.0, 4.0/)
NAMELIST /mynml/ x
PRINT mynml
END PROGRAM test_print
Expanded namelist reads are permitted. This causes an error if
-std=f95
is used. In the following example, the first element
of the array will be given the value 0.00 and the two succeeding
elements will be given the values 1.00 and 2.00.
&MYNML
X(1,1) = 0.00 , 1.00 , 2.00
/
When writing a namelist, if no DELIM=
is specified, by default a
double quote is used to delimit character strings. If -std=F95, F2003,
or F2008, etc, the delim status is set to ‘none’. Defaulting to
quotes ensures that namelists with character strings can be subsequently
read back in accurately.
X format descriptor without count field#
To support legacy codes, GNU Fortran permits the count field of the
X
edit descriptor in FORMAT
statements to be omitted.
When omitted, the count is implicitly assumed to be one.
PRINT 10, 2, 3
10 FORMAT (I1, X, I1)
Commas in FORMAT specifications#
To support legacy codes, GNU Fortran allows the comma separator
to be omitted immediately before and after character string edit
descriptors in FORMAT
statements. A comma with no following format
decriptor is permited if the -fdec-blank-format-item
is given on
the command line. This is considered non-conforming code and is
discouraged.
PRINT 10, 2, 3
10 FORMAT ('FOO='I1' BAR='I2)
print 20, 5, 6
20 FORMAT (I3, I3,)
Missing period in FORMAT specifications#
To support legacy codes, GNU Fortran allows missing periods in format
specifications if and only if -std=legacy
is given on the
command line. This is considered non-conforming code and is
discouraged.
REAL :: value
READ(*,10) value
10 FORMAT ('F4')
Default widths for F, G and I format descriptors#
To support legacy codes, GNU Fortran allows width to be omitted from format
specifications if and only if -fdec-format-defaults
is given on the
command line. Default widths will be used. This is considered non-conforming
code and is discouraged.
REAL :: value1
INTEGER :: value2
WRITE(*,10) value1, value1, value2
10 FORMAT ('F, G, I')
I/O item lists#
To support legacy codes, GNU Fortran allows the input item list
of the READ
statement, and the output item lists of the
WRITE
and PRINT
statements, to start with a comma.
Q exponent-letter#
GNU Fortran accepts real literal constants with an exponent-letter
of Q
, for example, 1.23Q45
. The constant is interpreted
as a REAL(16)
entity on targets that support this type. If
the target does not support REAL(16)
but has a REAL(10)
type, then the real-literal-constant will be interpreted as a
REAL(10)
entity. In the absence of REAL(16)
and
REAL(10)
, an error will occur.
BOZ literal constants#
Besides decimal constants, Fortran also supports binary (b
),
octal (o
) and hexadecimal (z
) integer constants. The
syntax is: prefix quote digits quote
, where the prefix is
either b
, o
or z
, quote is either '
or
"
and the digits are 0
or 1
for binary,
between 0
and 7
for octal, and between 0
and
F
for hexadecimal. (Example: b'01011101'
.)
Up to Fortran 95, BOZ literal constants were only allowed to initialize
integer variables in DATA statements. Since Fortran 2003 BOZ literal
constants are also allowed as actual arguments to the REAL
,
DBLE
, INT
and CMPLX
intrinsic functions.
The BOZ literal constant is simply a string of bits, which is padded
or truncated as needed, during conversion to a numeric type. The
Fortran standard states that the treatment of the sign bit is processor
dependent. Gfortran interprets the sign bit as a user would expect.
As a deprecated extension, GNU Fortran allows hexadecimal BOZ literal
constants to be specified using the X
prefix. That the BOZ literal
constant can also be specified by adding a suffix to the string, for
example, Z'ABC'
and 'ABC'X
are equivalent. Additionally,
as extension, BOZ literals are permitted in some contexts outside of
DATA
and the intrinsic functions listed in the Fortran standard.
Use -fallow-invalid-boz
to enable the extension.
Real array indices#
As an extension, GNU Fortran allows the use of REAL
expressions
or variables as array indices.
Unary operators#
As an extension, GNU Fortran allows unary plus and unary minus operators to appear as the second operand of binary arithmetic operators without the need for parenthesis.
X = Y * -Z
Implicitly convert LOGICAL and INTEGER values#
As an extension for backwards compatibility with other compilers, GNU
Fortran allows the implicit conversion of LOGICAL
values to
INTEGER
values and vice versa. When converting from a
LOGICAL
to an INTEGER
, .FALSE.
is interpreted as
zero, and .TRUE.
is interpreted as one. When converting from
INTEGER
to LOGICAL
, the value zero is interpreted as
.FALSE.
and any nonzero value is interpreted as .TRUE.
.
LOGICAL :: l
l = 1
INTEGER :: i
i = .TRUE.
However, there is no implicit conversion of INTEGER
values in
if
-statements, nor of LOGICAL
or INTEGER
values
in I/O operations.
Hollerith constants support#
GNU Fortran supports Hollerith constants in assignments, DATA
statements, function and subroutine arguments. A Hollerith constant is
written as a string of characters preceded by an integer constant
indicating the character count, and the letter H
or
h
, and stored in bytewise fashion in a numeric (INTEGER
,
REAL
, or COMPLEX
), LOGICAL
or CHARACTER
variable.
The constant will be padded with spaces or truncated to fit the size of
the variable in which it is stored.
Examples of valid uses of Hollerith constants:
complex*16 x(2)
data x /16Habcdefghijklmnop, 16Hqrstuvwxyz012345/
x(1) = 16HABCDEFGHIJKLMNOP
call foo (4h abc)
Examples of Hollerith constants:
integer*4 a
a = 0H ! Invalid, at least one character is needed.
a = 4HAB12 ! Valid
a = 8H12345678 ! Valid, but the Hollerith constant will be truncated.
a = 3Hxyz ! Valid, but the Hollerith constant will be padded.
In general, Hollerith constants were used to provide a rudimentary
facility for handling character strings in early Fortran compilers,
prior to the introduction of CHARACTER
variables in Fortran 77;
in those cases, the standard-compliant equivalent is to convert the
program to use proper character strings. On occasion, there may be a
case where the intent is specifically to initialize a numeric variable
with a given byte sequence. In these cases, the same result can be
obtained by using the TRANSFER
statement, as in this example.
integer(kind=4) :: a
a = transfer ("abcd", a) ! equivalent to: a = 4Habcd
The use of the -fdec
option extends support of Hollerith constants
to comparisons:
integer*4 a
a = 4hABCD
if (a .ne. 4habcd) then
write(*,*) "no match"
end if
Supported types are numeric (INTEGER
, REAL
, or COMPLEX
),
and CHARACTER
.
Character conversion#
Allowing character literals to be used in a similar way to Hollerith constants
is a non-standard extension. This feature is enabled using
-fdec-char-conversions and only applies to character literals of kind=1
.
Character literals can be used in DATA
statements and assignments with
numeric (INTEGER
, REAL
, or COMPLEX
) or LOGICAL
variables. Like Hollerith constants they are copied byte-wise fashion. The
constant will be padded with spaces or truncated to fit the size of the
variable in which it is stored.
Examples:
integer*4 x
data x / 'abcd' /
x = 'A' ! Will be padded.
x = 'ab1234' ! Will be truncated.
Cray pointers#
Cray pointers are part of a non-standard extension that provides a C-like pointer in Fortran. This is accomplished through a pair of variables: an integer “pointer” that holds a memory address, and a “pointee” that is used to dereference the pointer.
Pointer/pointee pairs are declared in statements of the form:
pointer ( <pointer> , <pointee> )
or,
pointer ( <pointer1> , <pointee1> ), ( <pointer2> , <pointee2> ), ...
The pointer is an integer that is intended to hold a memory address.
The pointee may be an array or scalar.
If an assumed-size array is permitted within the scoping unit, a
pointee can be an assumed-size array.
That is, the last dimension may be left unspecified by using a *
in place of a value. A pointee cannot be an assumed shape array.
No space is allocated for the pointee.
The pointee may have its type declared before or after the pointer statement, and its array specification (if any) may be declared before, during, or after the pointer statement. The pointer may be declared as an integer prior to the pointer statement. However, some machines have default integer sizes that are different than the size of a pointer, and so the following code is not portable:
integer ipt
pointer (ipt, iarr)
If a pointer is declared with a kind that is too small, the compiler will issue a warning; the resulting binary will probably not work correctly, because the memory addresses stored in the pointers may be truncated. It is safer to omit the first line of the above example; if explicit declaration of ipt’s type is omitted, then the compiler will ensure that ipt is an integer variable large enough to hold a pointer.
Pointer arithmetic is valid with Cray pointers, but it is not the same as C pointer arithmetic. Cray pointers are just ordinary integers, so the user is responsible for determining how many bytes to add to a pointer in order to increment it. Consider the following example:
real target(10)
real pointee(10)
pointer (ipt, pointee)
ipt = loc (target)
ipt = ipt + 1
The last statement does not set ipt
to the address of
target(1)
, as it would in C pointer arithmetic. Adding 1
to ipt
just adds one byte to the address stored in ipt
.
Any expression involving the pointee will be translated to use the value stored in the pointer as the base address.
To get the address of elements, this extension provides an intrinsic
function LOC()
. The LOC()
function is equivalent to the
&
operator in C, except the address is cast to an integer type:
real ar(10)
pointer(ipt, arpte(10))
real arpte
ipt = loc(ar) ! Makes arpte is an alias for ar
arpte(1) = 1.0 ! Sets ar(1) to 1.0
The pointer can also be set by a call to the MALLOC
intrinsic
(see MALLOC — Allocate dynamic memory).
Cray pointees often are used to alias an existing variable. For example:
integer target(10)
integer iarr(10)
pointer (ipt, iarr)
ipt = loc(target)
As long as ipt
remains unchanged, iarr
is now an alias for
target
. The optimizer, however, will not detect this aliasing, so
it is unsafe to use iarr
and target
simultaneously. Using
a pointee in any way that violates the Fortran aliasing rules or
assumptions is illegal. It is the user’s responsibility to avoid doing
this; the compiler works under the assumption that no such aliasing
occurs.
Cray pointers will work correctly when there is no aliasing (i.e., when they are used to access a dynamically allocated block of memory), and also in any routine where a pointee is used, but any variable with which it shares storage is not used. Code that violates these rules may not run as the user intends. This is not a bug in the optimizer; any code that violates the aliasing rules is illegal. (Note that this is not unique to GNU Fortran; any Fortran compiler that supports Cray pointers will ‘incorrectly’ optimize code with illegal aliasing.)
There are a number of restrictions on the attributes that can be applied
to Cray pointers and pointees. Pointees may not have the
ALLOCATABLE
, INTENT
, OPTIONAL
, DUMMY
,
TARGET
, INTRINSIC
, or POINTER
attributes. Pointers
may not have the DIMENSION
, POINTER
, TARGET
,
ALLOCATABLE
, EXTERNAL
, or INTRINSIC
attributes, nor
may they be function results. Pointees may not occur in more than one
pointer statement. A pointee cannot be a pointer. Pointees cannot occur
in equivalence, common, or data statements.
A Cray pointer may also point to a function or a subroutine. For example, the following excerpt is valid:
implicit none
external sub
pointer (subptr,subpte)
external subpte
subptr = loc(sub)
call subpte()
[...]
subroutine sub
[...]
end subroutine sub
A pointer may be modified during the course of a program, and this will change the location to which the pointee refers. However, when pointees are passed as arguments, they are treated as ordinary variables in the invoked function. Subsequent changes to the pointer will not change the base address of the array that was passed.
CONVERT specifier#
GNU Fortran allows the conversion of unformatted data between little-
and big-endian representation to facilitate moving of data
between different systems. The conversion can be indicated with
the CONVERT
specifier on the OPEN
statement.
See GFORTRAN_CONVERT_UNIT—Set conversion for unformatted I/O, for an alternative way of specifying
the data format via an environment variable.
Valid values for CONVERT
on most systems are:
CONVERT='NATIVE'
Use the native format. This is the default.CONVERT='SWAP'
Swap between little- and big-endian.CONVERT='LITTLE_ENDIAN'
Use the little-endian representation for unformatted files.CONVERT='BIG_ENDIAN'
Use the big-endian representation for unformatted files.
On POWER systems which support -mabi=ieeelongdouble
,
there are additional options, which can be combined with the others
with commas. Those are
CONVERT='R16_IEEE'
Use IEEE 128-bit format forREAL(KIND=16)
.CONVERT='R16_IBM'
Use IBMlong double
format for realREAL(KIND=16)
.
Using the option could look like this:
open(file='big.dat',form='unformatted',access='sequential', &
convert='big_endian')
The value of the conversion can be queried by using
INQUIRE(CONVERT=ch)
. The values returned are
'BIG_ENDIAN'
and 'LITTLE_ENDIAN'
.
CONVERT
works between big- and little-endian for
INTEGER
values of all supported kinds and for REAL
on IEEE systems of kinds 4 and 8. Conversion between different
‘extended double’ types on different architectures such as
m68k and x86_64, which GNU Fortran
supports as REAL(KIND=10)
and REAL(KIND=16)
, will
probably not work.
Note that the values specified via the GFORTRAN_CONVERT_UNIT environment variable will override the CONVERT specifier in the open statement. This is to give control over data formats to users who do not have the source code of their program available.
Using anything but the native representation for unformatted data carries a significant speed overhead. If speed in this area matters to you, it is best if you use this only for data that needs to be portable.
OpenMP#
OpenMP (Open Multi-Processing) is an application programming interface (API) that supports multi-platform shared memory multiprocessing programming in C/C++ and Fortran on many architectures, including Unix and Microsoft Windows platforms. It consists of a set of compiler directives, library routines, and environment variables that influence run-time behavior.
GNU Fortran strives to be compatible to the OpenMP Application Program Interface v4.5.
To enable the processing of the OpenMP directive !$omp
in
free-form source code; the c$omp
, *$omp
and !$omp
directives in fixed form; the !$
conditional compilation sentinels
in free form; and the c$
, *$
and !$
sentinels
in fixed form, gfortran needs to be invoked with the
-fopenmp
. This also arranges for automatic linking of the
GNU Offloading and Multi Processing Runtime Library
top.
The OpenMP Fortran runtime library routines are provided both in a
form of a Fortran 90 module named omp_lib
and in a form of
a Fortran include
file named omp_lib.h
.
An example of a parallelized loop taken from Appendix A.1 of the OpenMP Application Program Interface v2.5:
SUBROUTINE A1(N, A, B)
INTEGER I, N
REAL B(N), A(N)
!$OMP PARALLEL DO !I is private by default
DO I=2,N
B(I) = (A(I) + A(I-1)) / 2.0
ENDDO
!$OMP END PARALLEL DO
END SUBROUTINE A1
Note
-fopenmp
implies -frecursive
, i.e., all local arrays
will be allocated on the stack. When porting existing code to OpenMP,
this may lead to surprising results, especially to segmentation faults
if the stacksize is limited.
Note
On glibc-based systems, OpenMP enabled applications cannot be statically linked due to limitations of the underlying pthreads-implementation. It might be possible to get a working solution if -Wl,--whole-archive -lpthread -Wl,--no-whole-archive is added to the command line. However, this is not supported by gcc and thus not recommended.
OpenACC#
OpenACC is an application programming interface (API) that supports offloading of code to accelerator devices. It consists of a set of compiler directives, library routines, and environment variables that influence run-time behavior.
GNU Fortran strives to be compatible to the OpenACC Application Programming Interface v2.6.
To enable the processing of the OpenACC directive !$acc
in
free-form source code; the c$acc
, *$acc
and !$acc
directives in fixed form; the !$
conditional compilation
sentinels in free form; and the c$
, *$
and !$
sentinels in fixed form, gfortran needs to be invoked with
the -fopenacc
. This also arranges for automatic linking of
the GNU Offloading and Multi Processing Runtime Library
top.
The OpenACC Fortran runtime library routines are provided both in a
form of a Fortran 90 module named openacc
and in a form of a
Fortran include
file named openacc_lib.h
.
Argument list functions %VAL, %REF and %LOC#
GNU Fortran supports argument list functions %VAL
, %REF
and %LOC
statements, for backward compatibility with g77.
It is recommended that these should be used only for code that is
accessing facilities outside of GNU Fortran, such as operating system
or windowing facilities. It is best to constrain such uses to isolated
portions of a program–portions that deal specifically and exclusively
with low-level, system-dependent facilities. Such portions might well
provide a portable interface for use by the program as a whole, but are
themselves not portable, and should be thoroughly tested each time they
are rebuilt using a new compiler or version of a compiler.
%VAL
passes a scalar argument by value, %REF
passes it by
reference and %LOC
passes its memory location. Since gfortran
already passes scalar arguments by reference, %REF
is in effect
a do-nothing. %LOC
has the same effect as a Fortran pointer.
An example of passing an argument by value to a C subroutine foo.:
C
C prototype void foo_ (float x);
C
external foo
real*4 x
x = 3.14159
call foo (%VAL (x))
end
For details refer to the g77 manual https://gcc.gnu.org/onlinedocs/gcc-3.4.6/g77/index.html#Top.
Also, c_by_val.f
and its partner c_by_val.c
of the
GNU Fortran testsuite are worth a look.
Read/Write after EOF marker#
Some legacy codes rely on allowing READ
or WRITE
after the
EOF file marker in order to find the end of a file. GNU Fortran normally
rejects these codes with a run-time error message and suggests the user
consider BACKSPACE
or REWIND
to properly position
the file before the EOF marker. As an extension, the run-time error may
be disabled using -std=legacy.
STRUCTURE and RECORD#
Record structures are a pre-Fortran-90 vendor extension to create
user-defined aggregate data types. Support for record structures in GNU
Fortran can be enabled with the -fdec-structure
compile flag.
If you have a choice, you should instead use Fortran 90’s ‘derived types’,
which have a different syntax.
In many cases, record structures can easily be converted to derived types.
To convert, replace STRUCTURE /
structure-name
/
by TYPE
type-name
. Additionally, replace
RECORD /
structure-name
/
by
TYPE(
type-name
)
. Finally, in the component access,
replace the period (.
) by the percent sign (%
).
Here is an example of code using the non portable record structure syntax:
! Declaring a structure named ``item'' and containing three fields:
! an integer ID, an description string and a floating-point price.
STRUCTURE /item/
INTEGER id
CHARACTER(LEN=200) description
REAL price
END STRUCTURE
! Define two variables, an single record of type ``item''
! named ``pear'', and an array of items named ``store_catalog''
RECORD /item/ pear, store_catalog(100)
! We can directly access the fields of both variables
pear.id = 92316
pear.description = "juicy D'Anjou pear"
pear.price = 0.15
store_catalog(7).id = 7831
store_catalog(7).description = "milk bottle"
store_catalog(7).price = 1.2
! We can also manipulate the whole structure
store_catalog(12) = pear
print *, store_catalog(12)
This code can easily be rewritten in the Fortran 90 syntax as following:
! ``STRUCTURE /name/ ... END STRUCTURE'' becomes
! ``TYPE name ... END TYPE''
TYPE item
INTEGER id
CHARACTER(LEN=200) description
REAL price
END TYPE
! ``RECORD /name/ variable'' becomes ``TYPE(name) variable''
TYPE(item) pear, store_catalog(100)
! Instead of using a dot (.) to access fields of a record, the
! standard syntax uses a percent sign (%)
pear%id = 92316
pear%description = "juicy D'Anjou pear"
pear%price = 0.15
store_catalog(7)%id = 7831
store_catalog(7)%description = "milk bottle"
store_catalog(7)%price = 1.2
! Assignments of a whole variable do not change
store_catalog(12) = pear
print *, store_catalog(12)
GNU Fortran implements STRUCTURES like derived types with the following rules and exceptions:
Structures act like derived types with the
SEQUENCE
attribute. Otherwise they may contain no specifiers.Structures may contain a special field with the name
%FILL
. This will create an anonymous component which cannot be accessed but occupies space just as if a component of the same type was declared in its place, useful for alignment purposes. As an example, the following structure will consist of at least sixteen bytes:structure /padded/ character(4) start character(8) %FILL character(4) end end structure
Structures may share names with other symbols. For example, the following is invalid for derived types, but valid for structures:
structure /header/ ! ... end structure record /header/ header
Structure types may be declared nested within another parent structure. The syntax is:
structure /type-name/ ... structure [/<type-name>/] <field-list> ...
The type name may be ommitted, in which case the structure type itself is anonymous, and other structures of the same type cannot be instantiated. The following shows some examples:
structure /appointment/ ! nested structure definition: app_time is an array of two 'time' structure /time/ app_time (2) integer(1) hour, minute end structure character(10) memo end structure ! The 'time' structure is still usable record /time/ now now = time(5, 30) ... structure /appointment/ ! anonymous nested structure definition structure start, end integer(1) hour, minute end structure character(10) memo end structure
Structures may contain
UNION
blocks. For more detail see the section on UNION and MAP.Structures support old-style initialization of components, like those described in Old-style variable initialization. For array initializers, an initializer may contain a repeat specification of the form
<literal-integer> * <constant-initializer>
. The value of the integer indicates the number of times to repeat the constant initializer when expanding the initializer list.
UNION and MAP#
Unions are an old vendor extension which were commonly used with the
non-standard STRUCTURE and RECORD extensions. Use of UNION
and
MAP
is automatically enabled with -fdec-structure
.
A UNION
declaration occurs within a structure; within the definition of
each union is a number of MAP
blocks. Each MAP
shares storage
with its sibling maps (in the same union), and the size of the union is the
size of the largest map within it, just as with unions in C. The major
difference is that component references do not indicate which union or map the
component is in (the compiler gets to figure that out).
Here is a small example:
structure /myunion/
union
map
character(2) w0, w1, w2
end map
map
character(6) long
end map
end union
end structure
record /myunion/ rec
! After this assignment...
rec.long = 'hello!'
! The following is true:
! rec.w0 === 'he'
! rec.w1 === 'll'
! rec.w2 === 'o!'
The two maps share memory, and the size of the union is ultimately six bytes:
0 1 2 3 4 5 6 Byte offset
-------------------------------
| | | | | | |
-------------------------------
^ W0 ^ W1 ^ W2 ^
\-------/ \-------/ \-------/
^ LONG ^
\---------------------------/
Following is an example mirroring the layout of an Intel x86_64 register:
structure /reg/
union ! U0 ! rax
map
character(16) rx
end map
map
character(8) rh ! rah
union ! U1
map
character(8) rl ! ral
end map
map
character(8) ex ! eax
end map
map
character(4) eh ! eah
union ! U2
map
character(4) el ! eal
end map
map
character(4) x ! ax
end map
map
character(2) h ! ah
character(2) l ! al
end map
end union
end map
end union
end map
end union
end structure
record /reg/ a
! After this assignment...
a.rx = 'AAAAAAAA.BBB.C.D'
! The following is true:
a.rx === 'AAAAAAAA.BBB.C.D'
a.rh === 'AAAAAAAA'
a.rl === '.BBB.C.D'
a.ex === '.BBB.C.D'
a.eh === '.BBB'
a.el === '.C.D'
a.x === '.C.D'
a.h === '.C'
a.l === '.D'
Type variants for integer intrinsics#
Similar to the D/C prefixes to real functions to specify the input/output types, GNU Fortran offers B/I/J/K prefixes to integer functions for compatibility with DEC programs. The types implied by each are:
B - INTEGER(kind=1)
I - INTEGER(kind=2)
J - INTEGER(kind=4)
K - INTEGER(kind=8)
GNU Fortran supports these with the flag -fdec-intrinsic-ints
.
Intrinsics for which prefixed versions are available and in what form are noted
in Intrinsic Procedures. The complete list of supported intrinsics is
here:
Intrinsic |
B |
I |
J |
K |
---|---|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
AUTOMATIC and STATIC attributes#
With -fdec-static
GNU Fortran supports the DEC extended attributes
STATIC
and AUTOMATIC
to provide explicit specification of entity
storage. These follow the syntax of the Fortran standard SAVE
attribute.
STATIC
is exactly equivalent to SAVE
, and specifies that
an entity should be allocated in static memory. As an example, STATIC
local variables will retain their values across multiple calls to a function.
Entities marked AUTOMATIC
will be stack automatic whenever possible.
AUTOMATIC
is the default for local variables smaller than
-fmax-stack-var-size
, unless -fno-automatic
is given. This
attribute overrides -fno-automatic
, -fmax-stack-var-size
, and
blanket SAVE
statements.
Examples:
subroutine f
integer, automatic :: i ! automatic variable
integer x, y ! static variables
save
...
endsubroutine
subroutine f
integer a, b, c, x, y, z
static :: x
save y
automatic z, c
! a, b, c, and z are automatic
! x and y are static
endsubroutine
! Compiled with -fno-automatic
subroutine f
integer a, b, c, d
automatic :: a
! a is automatic; b, c, and d are static
endsubroutine
Extended math intrinsics#
GNU Fortran supports an extended list of mathematical intrinsics with the
compile flag -fdec-math
for compatability with legacy code.
These intrinsics are described fully in Intrinsic Procedures where it is
noted that they are extensions and should be avoided whenever possible.
Specifically, -fdec-math
enables the COTAN intrinsic, and
trigonometric intrinsics which accept or produce values in degrees instead of
radians. Here is a summary of the new intrinsics:
Radians |
Degrees |
---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
* Enabled with -fdec-math
.
For advanced users, it may be important to know the implementation of these functions. They are simply wrappers around the standard radian functions, which have more accurate builtin versions. These functions convert their arguments (or results) to degrees (or radians) by taking the value modulus 360 (or 2*pi) and then multiplying it by a constant radian-to-degree (or degree-to-radian) factor, as appropriate. The factor is computed at compile-time as 180/pi (or pi/180).
Form feed as whitespace#
Historically, legacy compilers allowed insertion of form feed characters (’f’, ASCII 0xC) at the beginning of lines for formatted output to line printers, though the Fortran standard does not mention this. GNU Fortran supports the interpretation of form feed characters in source as whitespace for compatibility.
TYPE as an alias for PRINT#
For compatibility, GNU Fortran will interpret TYPE
statements as
PRINT
statements with the flag -fdec
. With this flag asserted,
the following two examples are equivalent:
TYPE *, 'hello world'
PRINT *, 'hello world'
%LOC as an rvalue#
Normally %LOC
is allowed only in parameter lists. However the intrinsic
function LOC
does the same thing, and is usable as the right-hand-side of
assignments. For compatibility, GNU Fortran supports the use of %LOC
as
an alias for the builtin LOC
with -std=legacy
. With this
feature enabled the following two examples are equivalent:
integer :: i, l
l = %loc(i)
call sub(l)
integer :: i
call sub(%loc(i))
.XOR. operator#
GNU Fortran supports .XOR.
as a logical operator with -std=legacy
for compatibility with legacy code. .XOR.
is equivalent to
.NEQV.
. That is, the output is true if and only if the inputs differ.
Bitwise logical operators#
With -fdec
, GNU Fortran relaxes the type constraints on
logical operators to allow integer operands, and performs the corresponding
bitwise operation instead. This flag is for compatibility only, and should be
avoided in new code. Consider:
INTEGER :: i, j
i = z'33'
j = z'cc'
print *, i .AND. j
In this example, compiled with -fdec
, GNU Fortran will
replace the .AND.
operation with a call to the intrinsic
function, yielding the bitwise-and of i
and j
.
Note that this conversion will occur if at least one operand is of integral
type. As a result, a logical operand will be converted to an integer when the
other operand is an integer in a logical operation. In this case,
.TRUE.
is converted to 1
and .FALSE.
to 0
.
Here is the mapping of logical operator to bitwise intrinsic used with
-fdec
:
Operator |
Intrinsic |
Bitwise operation |
---|---|---|
|
|
complement |
|
|
intersection |
|
|
union |
|
|
exclusive or |
|
|
complement of exclusive or |
Extended I/O specifiers#
GNU Fortran supports the additional legacy I/O specifiers
CARRIAGECONTROL
, READONLY
, and SHARE
with the
compile flag -fdec
, for compatibility.
- CARRIAGECONTROL#
The
CARRIAGECONTROL
specifier allows a user to control line termination settings between output records for an I/O unit. The specifier has no meaning for readonly files. WhenCARRAIGECONTROL
is specified upon opening a unit for formatted writing, the exactCARRIAGECONTROL
setting determines what characters to write between output records. The syntax is:OPEN(..., CARRIAGECONTROL=cc)
Where cc is a character expression that evaluates to one of the following values:
'LIST'
One line feed between records (default)
'FORTRAN'
Legacy interpretation of the first character (see below)
'NONE'
No separator between records
With
CARRIAGECONTROL='FORTRAN'
, when a record is written, the first character of the input record is not written, and instead determines the output record separator as follows:Leading character
Meaning
Output separating character(s)
'+'
Overprinting
Carriage return only
'-'
New line
Line feed and carriage return
'0'
Skip line
Two line feeds and carriage return
'1'
New page
Form feed and carriage return
'$'
Prompting
Line feed (no carriage return)
CHAR(0)
Overprinting (no advance)
None
- READONLY#
The
READONLY
specifier may be given upon opening a unit, and is equivalent to specifyingACTION='READ'
, except that the file may not be deleted on close (i.e.CLOSE
withSTATUS="DELETE"
). The syntax is:OPEN(..., READONLY)
- SHARE#
The
SHARE
specifier allows system-level locking on a unit upon opening it for controlled access from multiple processes/threads. TheSHARE
specifier has several forms:OPEN(..., SHARE=sh) OPEN(..., SHARED) OPEN(..., NOSHARED)
Where sh in the first form is a character expression that evaluates to a value as seen in the table below. The latter two forms are aliases for particular values of sh:
Explicit form
Short form
Meaning
SHARE='DENYRW'
NOSHARED
Exclusive (write) lock
SHARE='DENYNONE'
SHARED
Shared (read) lock
In general only one process may hold an exclusive (write) lock for a given file at a time, whereas many processes may hold shared (read) locks for the same file.
The behavior of locking may vary with your operating system. On POSIX systems, locking is implemented with
fcntl
. Consult your corresponding operating system’s manual pages for further details. Locking viaSHARE=
is not supported on other systems.
Legacy PARAMETER statements#
For compatibility, GNU Fortran supports legacy PARAMETER statements without
parentheses with -std=legacy
. A warning is emitted if used with
-std=gnu
, and an error is acknowledged with a real Fortran standard
flag (-std=f95
, etc…). These statements take the following form:
implicit real (E)
parameter e = 2.718282
real c
parameter c = 3.0e8
Default exponents#
For compatibility, GNU Fortran supports a default exponent of zero in real
constants with -fdec
. For example, 9e
would be
interpreted as 9e0
, rather than an error.