# Introduction
This article shows how to wrap a pragma in a macro for better readability,
portability, and maintenance. It is in the form of an extended example. The
entire example is shown first. Then it is commented upon a few lines at a
time.
This example uses pragmas that are specific to the C6000 compiler. The
general techniques shown can be applied to any pragma.
# Full Example
```
/* pragma.c */
#include
#ifdef __TI_COMPILER_VERSION__
#define PRAGMA(x) _Pragma(#x)
#define LOOP_COUNT_INFO(min, multiple) \
PRAGMA(MUST_ITERATE(min,,multiple))
#define VAR_IN_SECTION(var, section) \
PRAGMA(DATA_SECTION(var, #section))
#define PTR_IS_ALIGNED(ptr, pow2) \
_nassert(((unsigned int) (ptr) & (pow2)-1) == 0);
#else
#define LOOP_COUNT_INFO(min, multiple)
#define VAR_IN_SECTION(var, section)
#define PTR_IS_ALIGNED(ptr, pow2)
#endif
VAR_IN_SECTION(array, special)
int array[100];
int sum(int *p, int length)
{
int i;
int sum = 0;
PTR_IS_ALIGNED(p, 8)
LOOP_COUNT_INFO(8, 4)
for (i = 0; i < length; i++)
sum += p[i];
return sum;
}
```
# Discussion
The system header file assert.h
```
#include
```
is included because it defines the _nassert macro referred to by
PTR_IS_ALIGNED.
The test against \_\_TI\_COMPILER\_VERSION\_\_
```
#ifdef __TI_COMPILER_VERSION__
```
is how the macros are defined to proper effect when used under a TI compiler,
or defined to do nothing when used under some other compiler. The identifier
\_\_TI\_COMPILER\_VERSION\_\_ is predefined by TI compilers.
These lines
```
#define PRAGMA(x) _Pragma(#x)
#define LOOP_COUNT_INFO(min, multiple) \
PRAGMA(MUST_ITERATE(min,,multiple))
```
define the LOOP_COUNT_INFO macro, which gives the compiler extra information
about how many times a loop may iterate. It wraps usage of the MUST_ITERATE
pragma.
Pragmas, as first introduced in the C language, are preprocessing directives
which perform some compiler specific action. The general form of pragmas is
defined by the C language
```
#pragma token-sequence
```
Any further details are left to each compiler to define. The TI compilers
define several pragmas, two of which are used in the example. Consult the
Compiler User's Guide for your target for more information on what specific
pragmas are available, and how they work.
One problem with supplying a pragma in the form a preprocessing directive is
that it cannot be generated by use of another preprocessing macro. This
deficiency gives rise to the special preprocessing operator _Pragma. The
operand of _Pragma is a string literal. This
```
_Pragma(sequence of tokens)
```
is the same as
```
#pragma sequence of tokens
```
Preprocessing macros can generate the _Pragma operator.
A first attempt at writing a macro to generate a _Pragma might be as follows
```
/* WRONG!!! */
#define LOOP_COUNT_INFO(min, multiple) \
_Pragma("MUST_ITERATE(min,,multiple)")
```
That doesn't work. The min and multiple arguments of the LOOP_COUNT_INFO
macro are not replaced inside the quotes of the _Pragma operator. This can
be seen with the preprocessing listing feature of the compiler.
The compiler option --gen_preprocessor_listing creates a preprocessor listing
file. It has the same name as the source file, with the file extension
changed to .rl.
```
C:\some\dir>cl6x --gen_preprocessor_listing pragma.c
```
Inspect the file pragma.rl. These lines appear near the end.
```
N LOOP_COUNT_INFO(8, 4)
X _Pragma("MUST_ITERATE(min,,multiple)")
```
Every line in the preprocessor listing file begins with a capital letter
which identifies it. N means a normal line of source. X is that same line
after preprocessing.
Now you can see that, even though the LOOP_COUNT_INFO macro is invoked with
min=8 and multiple=4, those arguments are not replaced inside the quotes of
the argument to _Pragma.
This difficulty is overcome by using a helper macro named PRAGMA:
```
#define PRAGMA(x) _Pragma(#x)
```
This macro uses the '#' operator to make a string of its argument, and applies
the _Pragma operator to it. When it is invoked, its argument x is evaluated
before it is changed into a string. Therefore, in this example
```
#define LOOP_COUNT_INFO(min, multiple) \
PRAGMA(MUST_ITERATE(min,,multiple))
```
The arguments min and multiple of the LOOP_COUNT_INFO macro are replaced prior
to invocation of the PRAGMA macro. This can be verified by using the
preprocessor listing file like before.
```
N LOOP_COUNT_INFO(8, 4)
X _Pragma("MUST_ITERATE(8,,4)")
```
The MUST_ITERATE pragma takes 3 arguments, in this order:
* min : indicates the loop will iterate at least this many times
* max : indicates the loop will iterate a maximum of this many times
* multiple : indicates the loop will always iterate a multiple of this many times
Any of the arguments may be omitted. The maximum is the most often omitted
argument. That is why LOOP_COUNT_INFO does not account for it, but writes the
MUST_ITERATE arguments as min,,multiple.
The lines
```
#define VAR_IN_SECTION(var, section) \
PRAGMA(DATA_SECTION(var, #section))
```
wrap usage of the DATA_SECTION pragma. This pragma instructs the compiler to
place the global data object in the given section instead of the default
section .bss. This allows, among other things, more precise placement of the
data when linking. Note the use of the '#' operator on the section name
argument. This is because the DATA_SECTION pragma itself, whether invoked via
\#pragma or _Pragma, requires that the section name argument be a quoted string
literal.
The lines
```
#define PTR_IS_ALIGNED(ptr, pow2) \
_nassert(((unsigned int) (ptr) & (pow2)-1) == 0);
```
are similar to a pragma in effect, yet do not use a pragma. The intrinsic
_nassert is related to the assert macro defined in assert.h. While the assert
macro results in code that checks its expression at runtime and issues a
message if it is false, the _nassert intrinsic results in no code. The
expression to _nassert is presumed by the compiler to always be true. This
extra knowledge of the source often leads to improved optimization. In this
case, the PTR_IS_ALIGNED macro indicates the pointer expression is always
aligned on an address at the given power of 2, which can lead to the use of
more efficient data access instructions that require such alignment.
The lines
```
#else
#define LOOP_COUNT_INFO(min, multiple)
#define VAR_IN_SECTION(var, section)
#define PTR_IS_ALIGNED(ptr, pow2)
#endif
```
define those macros to do nothing when a non-TI compiler is being used.
The rest of the example shows straightforward use of the macros.
Please make careful note of the use, or non-use, of semicolons throughout the
example. A semicolon must not appear between a _Pragma and the statement it
affects. That is why the LOOP_COUNT_INFO and VAR_IN_SECTION macros do not end
in semicolons when they are defined or invoked. A semicolon must appear at
the end of an _nassert statement. Thus a semicolon must be part of either the
definition or the invocation of the PTR_IS_ALIGNED macro. The semicolon is
written in the definition so that all the macros are consistently invoked
without a semicolon.
For more details on _Pragma, perform an Internet search on the term *Pragma
operator*.