The
#pragma
directive is a standard method for implementing
features that vary from one compiler to the next.
This chapter describes the
implementation-specific pragmas that are supported on the C compiler:
#pragma environment
(Section 3.1)
#pragma inline
(Section 3.2)
#pragma intrinsic
and
#pragma function
(Section 3.3)
#pragma linkage
(Section 3.4)
#pragma member_alignment
(Section 3.5)
#pragma message
(Section 3.6)
#pragma pack
(Section 3.7)
#pragma pointer_size
(Section 3.8)
#pragma use_linkage
(Section 3.9)
#pragma weak
(Section 3.10)
Pragmas supported by all implementations of DEC C are described in the DEC C Language Reference Manual.
Some pragmas are subject to macro expansion. The DEC C Language Reference Manual lists these pragmas. It also describes the use of double underscores as prefixes to pragma names and keywords to avoid macro expansion problems when porting a program that defines a macro with the same name as a pragma name or keyword.
The
#pragma environment
directive allows you to set, save, and restore the state of all context pragmas.
The context pragmas are:
#pragma member_alignment
#pragma message
#pragma pack
#pragma pointer_sizeA context pragma can save and restore previous states, usually before and after including a header file that might also use the same type of pragma.
The
#pragma environment
directive
protects include files from compilation contexts set by encompassing programs,
and protects encompassing programs from contexts set in header files that
they include.
This pragma has the following syntax:
#pragma environment [
cmd_line | hdr_defaults | restore | save
]
Sets the states of all of the context pragmas set on the command line. You can use this pragma to protect header files from environment pragmas that take effect before the header file is included.
Sets the states of all of the context pragmas to their default
values.
This is equivalent to the situation in which a program with no command-line
options and no pragmas is compiled, except that this pragma sets the pragma
message state to
#pragma nostandard, as
is appropriate for header files.
restoreRestores the current state of every context pragma.
saveSaves the current state of every context pragma.
Without requiring further changes to the source code, you can use
#pragma environment
to protect header files from things such as
language enhancements that might introduce additional compilation contexts.
A header file can selectively inherit the state of a pragma from the including file and then use additional pragmas as needed to set the compilation to nondefault states. For example:
#ifdef _ _pragma_environment #pragma _ _environment save [1] #pragma _ _environment header_defaults [2] #pragma member_alignment restore [3] #pragma member_alignment save [4] #endif . . /*contents of header file*/ . #ifdef _ _pragma_environment #pragma _ _environment restore #endif
In this example:
Saves the state of all context pragmas. [Return to example]
Sets the default compilation environment. [Return to example]
Pops the member alignment context from the
#pragma member_alignment
stack that was pushed by
#pragma
_ _environment save, restoring the member alignment context
to its pre-existing state.
[Return to example]
Pushes the member alignment context back onto
the stack so that the
#pragma _ _environment restore
can pop the entry.
[Return to example]
Therefore, the header file is protected from all pragmas, except for the member alignment context that the header file was meant to inherit.
Function inlining is the inline expansion of function calls, replacing the function call with the function code itself. Inline expansion of functions reduces execution time by eliminating function-call overhead and allowing the compiler's general optimization methods to apply across the expanded code. Compared with the use of function-like macros, function inlining has the following advantages:
Arguments are evaluated only once.
Overuse of parentheses is not necessary to avoid problems with precedence.
Actual expansion can be controlled from the command line.
The semantics are as if inline expansion had not occurred. You cannot get this behavior using macros.
The following preprocessor directives control function inlining:
#pragma inline (id, ...)
#pragma noinline (id, ...)
Where id is a function identifier:
If a function is named in a
#pragma inline
directive, calls to that function are expanded as inline code,
if possible.
If a function is named in a
#pragma noinline
directive, calls to that function are not expanded as inline code.
If a function is named in both a
#pragma inline
and a
#pragma noinline
directive,
an error message is issued.
If a function is to be expanded inline, you must place the function definition in the same module as the function call. The definition can appear either before or after the function call.
The
cc
command options
-O3,
-O4,
-inline size,
-inline speed, or
-inline all
cause the compiler to attempt to expand
calls to functions named in neither a
#pragma inline
nor a
#pragma noinline
directive
as inline code whenever appropriate, as determined by the following function
characteristics:
Size
Number of times the function is called
Conformance to the following restrictions:
The function does not take a parameter's address.
A field of a
struct
argument.
An argument
that is a pointer to a
struct
is not restricted.
The function does not use the
varargs
or
stdarg
package to access the function's arguments because they require
arguments to be in adjacent memory locations, and inline expansion may violate
that requirement.
For optimization level
-O2, the C compiler inlines
small static routines only.
The
#pragma inline
directive causes
inline expansion regardless of the size or number of times the specified functions
are called.
Certain functions can be
declared to be
intrinsic.
Intrinsic functions are functions
for which the C compiler generates optimized code in certain situations, possibly
avoiding a function call.
Table 3-1 shows the functions that can be declared to be intrinsic.
abs |
fabs |
labs |
|
printf |
fprintf |
sprintf |
|
strcpy |
strlen |
memcpy |
|
memmove |
memset |
alloca |
|
bcopy |
bzero |
To control whether a function is treated as an intrinsic, use one of the following directives (where func_name_list is a comma-separated list of function names optionally enclosed in parentheses):
#pragma intrinsic [(]
func_name_list [)]
#pragma function [(] func_name_list [)]
#pragma function ()
The
#pragma intrinsic
directive enables
intrinsic treatment of a function.
When the
#pragma intrinsic
directive is turned on, the compiler understands how the functions
work and is thus able to generate more efficient code.
A declaration for the
function must be in effect at the time the pragma is processed.
The
#pragma function
directive disables
the intrinsic treatment of a function.
A
#pragma function
directive with an empty
func_name_list
disables intrinsic processing for all functions.
Some standard library functions also have built-in counterparts in the compiler. A built-in is a synonym name for the function and is equivalent to declaring the function to be intrinsic. The following built-ins (and their built-in names) are provided:
| Function | Synonym |
abs |
_ _builtin_abs |
labs |
_ _builtin_labs |
fabs |
_ _builtin_fabs |
alloca |
_ _builtin_alloca |
strcpy |
_ _builtin_strcpy |
Several methods are available for using intrinsics and built-ins.
The
header files containing the declarations of the functions contain the
#pragma intrinsic
directive for the functions shown
in
Table 3-1.
To enable the directive, you must define
the preprocessor macro
_INTRINSICS.
For
alloca, all that is necessary is to include
alloca.h.
For example, to get the intrinsic version of
abs,
a program should either include
stdlib.h
and compile with
-D_INTRINSICS
or define
_INTRINSICS
with a
#define
directive before including
stdlib.h.
To enable built-in processing, use the
-D
switch.
For example, to enable the
fabs
built-in, the
proc.c
program is compiled with one of the following:
%cc -Dfabs=_ _builtin_fabs prog.c%cc -Dabs=_ _builtin_abs prog.c
Optimization of the preceding functions varies according to the function and how it is used:
The following functions are inlined:
abs
fabs
labs
allocaThe function call overhead is removed.
In certain instances, the
printf
and
fprintf
functions are converted to call
puts,
putc,
fputs, or
fputc
(or
their equivalents), depending on the format string and the number and types
of arguments.
In certain instances, the
sprintf
function
is inlined or converted to a call to
strcpy.
The
strcpy
function is inlined if the source
string (the second argument) is a string literal.
The
#pragma linkage
directive allows you to specify linkage
types.
A linkage type specifies how a function uses a set of registers.
It
allows you to specify the registers that a function uses.
It also allows you
to specify the characteristics of a function (for example, the registers in
which it passes parameters or returns values) and the registers that it can
modify.
The
#pragma use_linkage
directive
associates a previously defined linkage with a function (see
Section 3.9).
The
#pragma linkage
directive affects
both the call site and function compilation (if the function is written in
C).
If the function is written in assembler, you can use "linkage pragma"
to describe how the assembler uses registers.
The
#pragma linkage
directive has
the following format:
#pragma linkage
linkage-name
= (characteristics)
Identifies the linkage type being defined. It has the form of a C identifier. Linkage types have their own name space, so their names will not conflict with other identifiers or keywords in the compilation unit.
Specifies information about where parameters will be passed, where the results of the function are to be received, and what registers are modified by the function call.
You must specify a
register-list.
A
register-list
is a comma-separated list of register names, either
rn
or
fn.
A
register-list
can
also contain parenthesized sublists.
Use the
register-list
to describe arguments and function result types that are structures, where
each member of the structure is passed in a single register.
For example:
parameters(r0,(f0,f1))
The preceding example is
a function with two parameters.
The first parameter is passed in register
r0.
The second parameter is a structure type with two floating-point
members, which are passed in registers
f0
and
f1.
The following list of characteristics can be specified as a parenthesized list of comma-separated items. Note, these keywords can be supplied in any order.
parameters (register-list)
The
parameters
characteristic passes arguments to
a routine in specific registers.
Each item in the register-list describes one parameter that is passed to the routine.
You can pass structure arguments by value, with the restriction that each member of the structure is passed in a separate parameter location. Doing so, however, may produce code that is slower because of the large number of registers used. The compiler does not diagnose this condition.
Valid registers for the
parameters
option include
integer registers
r0
through
r25
and
floating-point registers
f0
through
f30.
Structure types require at least one register for each field. The compiler verifies that the number of registers required for a structure type is the same as the number provided in the pragma.
result (register-list)
The compiler needs to know which registers will be used to return the
value from the function.
Use the
result
characteristic
to pass this information.
If a function does not return a value (that is, the function has a return
type of
void), do not specify
result
as part of the linkage.
Valid registers for the
register
option include general-purpose
registers
r0
through
r25
and floating-point
registers
f0
through
f30.
preserved (register-list)nopreserve (register-list)notused (register-list)notneeded ((lp))
The compiler needs to know which registers are used by the function
and which are not, and of those used, whether they are preserved across the
function call.
To specify this information, use the
preserved,
nopreserve,
notused, and
notneeded
options:
A
preserved
register contains the same
value after a call to the function as it did before the call.
A
nopreserve
register does not necessarily
contain the same value after a call to the function as it did before the call.
A
notused
register is not used in any way
by the called function.
The
notneeded
characteristic indicates
that certain items are not needed by the routines using this linkage.
The
lp
keyword specifies that the Linkage Pointer register (r27) does not need to be set up when calling the specified functions.
The linkage pointer is required when the called function accesses global or
static
data.
You must determine whether it is valid to specify that
the register is not needed.
Valid registers for the
preserved,
nopreserve, and
notused
options include general-purpose
registers
r0
through
r30
and floating-point
registers
f0
through
f30.
The
#pragma linkage
directive
does not support structures containing nested substructures as parameters
or function return types with special linkages.
Functions that have a special
linkage associated with them do not support parameters or return types that
have a union type.
The following characteristics specify a
simple-register-list
containing two elements (registers
f3
and
f4); and a
register-list
containing two
elements (register
r0
and a sublist containing the registers
f0
and
f1):
nopreserve(f3,f4) parameters(r0,(f0,f1))
The following example shows a linkage using such characteristics:
#pragma linkage my_link=(nopreserve(f3,f4),
parameters(r0,(f0,f1)),
notneeded (lp))
The parenthesized notation
in a
register-list
describes arguments and function
return values of type
struct, where each member of the
struct
is passed in a single register.
In the following example,
sample_linkage
specifies two parameters -- the first is passed
in registers
r0,
r1, and
r2
and the second is passed in
f1:
struct sample_struct_t {
int A, B;
short C;
} sample_struct;
#pragma linkage sample_linkage = (parameters ((r0, r1, r2), f1))
void sub (struct sample_struct_t p1, double p2) { }
main()
{
double d;
sub (sample_struct, d);
}
By default, the
compiler aligns structure members on natural boundaries.
Use the
#pragma [no]member_alignment
preprocessor directive
to determine the byte alignment of structure members.
This pragma has the following formats:
#pragma member_alignment [ save | restore
]
#pragma nomember_alignment
save | restoreSaves the current state of the member alignment (including
pack alignment) and restores the previous state, respectively.
The ability
to control the state is necessary for writing header files that require
member_alignment
or
nomember_alignment, or that
require inclusion in a
member_alignment
that is already
set.
Use
#pragma member_alignment
to specify
natural-boundary alignment of structure members.
When
#pragma member_alignment
is used, the compiler aligns structure members on the next boundary
appropriate to the type of the member, rather than on the next byte.
For instance,
an
int
variable is aligned on the next longword boundary;
a
short
variable is aligned on the next word boundary.
Where the
#pragma [no]member_alignment
directives allow you to choose between natural and byte alignment, the
pragma pack
directive allows you to specify structure
member alignment on byte, word, longword, or quadword boundaries.
See
Section 3.7
for more information on
#pragma pack.
With any combination of
#pragma member_alignment,
#pragma nomember_alignment,
and
#pragma pack, each pragma remains in
effect until the next one is encountered.
The
#pragma message
directive controls the issuance of
individual diagnostic messages or groups of diagnostic messages.
The use of
this pragma overrides any command-line options that may affect the issuance
of messages.
The
#pragma message
directive has
the following formats:
#pragma message [ enable | disable
] (message-list)
#pragma message [ save | restore ]
enable | disable
message-list
enable
-- Enables issuance of the
messages specified in the message list.
disable
-- Disables issuance of the
messages specified in the message list.
message-list
The message-list can be one of the following:
A single message identifier.
Use the
-verbose
option on the
cc
command to obtain the message identifier.
The name of a message group:
ALL
-- Messages in the compiler
CHECK
-- Messages about potentially
poor coding practices
PORTABLE
-- Messages about portability
A single message identifier enclosed in parentheses.
A message group name enclosed in parentheses.
A comma-separated list of message identifiers or group names, freely mixed, enclosed in parentheses.
Only messages of severity Warning or Information can be disabled. If the message has severity of Error or Fatal, it is issued regardless of any attempt to disable it.
The default is to issue all diagnostic messages for the selected compiler
mode except those in the
CHECK
group, which must be explicitly
enabled to display its messages.
save | restore
save
-- Saves the current state of
which messages are enabled and disabled.
restore
-- Restores the previous state
of which messages are enabled and disabled.
The
save
and
restore
options
are useful primarily within header files.
The
#pragma pack
directive changes the alignment restrictions on all members of
a structure.
The pragma must appear before the entire structure definition
because it acts on the whole structure.
The syntax of this pragma is as follows:
#pragma pack (n)
The
n
is a number
(such as 1, 2, or 4) that specifies that subsequent structure members are
to be aligned on
n-byte boundaries.
If you supply
a value of 0 (zero) for
n, the alignment reverts
to the default, which may have been set by the
-Zpn
option on the
cc
command.
The
#pragma pointer_size
directive
controls pointer size allocation for the following:
References
Pointer declarations
Function declarations
Array declarations
This pragma has the following syntax:
#pragma pointer_size { long | short | 64 | 32
} | { restore | save }
long | 64Sets all pointer sizes as 64 bits in all declarations that
follow this directive, until the compiler encounters another
#pragma pointer_size
directive.
short | 32Sets all pointer sizes as 32 bits in declarations that follow
this directive, until the compiler encounters another
#pragma pointer_size
directive.
save | restoreSaves the current pointer size and restores the saved pointer
size, respectively.
The
save
and
restore
options are particularly useful for specifying mixed pointer support and for
protecting header files that interface to older objects.
Objects compiled
with multiple pointer size pragmas will not be compatible with old objects,
and the compiler cannot discern that incompatible objects are being mixed.
The use of short pointers is restricted to DEC C++ and DEC C compilers residing on a Tru64 UNIX system. Programs should not attempt to pass short pointers from C++ routines to routines written in any language other than the C programming language. Also, DEC C++ may require explicit conversion of short pointers to long pointers in applications that use short pointers. You should first port those applications in which you are considering using short pointers, and then analyze them to determine if short pointers would be beneficial. A difference in the size of a pointer in a function declaration is not sufficient to overload a function.
The C compiler issues an error level diagnostic if it encounters any of the following conditions:
Two functions defined differ only with respect to pointer sizes.
Two functions differ in return type only with respect to pointer size.
After
defining a special linkage with the
#pragma linkage
directive, as described in
Section 3.4,
use the
#pragma use_linkage
directive to
associate the linkage with a function.
This pragma has the following format:
#pragma use_linkage
linkage-name (routine1, routine2, ...)
Specifies the name of a linkage previously defined by the
#pragma linkage
directive.
Specifies the names of functions that you want associated with the specified linkage.
The
#pragma use_linkage
directive must appear in the source file before any use or definition of the
specified routines.
Otherwise, the results are unpredictable.
The following example defines a special linkage and associates it with a routine that takes three integer parameters and returns a single integer result in the same location where the first parameter was passed:
#pragma linkage example_linkage (parameters(r16, r17, r19), result(r16))
#pragma use_linkage example_linkage (sub)
int sub (int p1, int p2, short p3);
main()
{
int result;
result = sub (1, 2, 3);
}
In this example, the
result(r16)
option indicates
that the function result will be returned in register
r16
instead of the usual location (r0).
The
parameters
option indicates that the three parameters passed to
sub
should be passed in registers
r16,
r17, and
r19.
The
#pragma weak
directive defines a new weak external symbol and associates this
new symbol with an external symbol.
The syntax for this pragma is as follows:
#pragma weak (secondary-name,
primary-name)
See Section 2.8 for information on strong and weak symbols.