United States

Compaq C

# Compaq C
Language Reference Manual

Previous | Contents | Index

## 8.1.2 Function-Like Form

The function-like form of macro definition includes a list of parameters. References to such macros look like function calls. When a function is called, control passes from the program to the function at run time; when a macro is referenced, source code is inserted into the program at compile time. The parameters are replaced by the corresponding arguments, and the text is inserted into the program stream.

If there is a ... in the identifier-list in the macro definition, then the trailing arguments, including any separating comma preprocessing tokens, are merged to form a single item: the variable arguments. The number of arguments so combined is such that, following the merger, the number of arguments is one more than the number of parameters in the macro definition (excluding the ...).

An identifier __VA_ARGS__ that occurs in the replacement-list of a function-like macro that uses ellipsis notation in the arguments is treated as if it were a parameter, and the variable arguments form the preprocessing tokens used to replace it.

If the replacement list is omitted from the macro definition, the entire macro reference disappears from the source text.

The library macro `_toupper` , available on some systems in the `ctype.h` header file, is a good example of macro replacement. This macro is defined as follows:

    #define  _toupper(c)  ((c) >= 'a'  &&  (c) <= 'z'  ? (c) & 0X5F : (c))

When the macro `_toupper` is referenced, the compiler replaces the macro and its parameter with the replacement list from the directive, substituting the argument of the macro reference for each occurrence of the parameter ( `c` in this case) in the replacement list.

The replacement list of C source code can be translated in the following manner: if parameter `c` is a lowercase letter (between `'a'` and `'z'` ), the expression evaluates to an uppercase letter ( `c & 0X5F` ); otherwise, it evaluates to the character as specified. This replacement list uses the if-then-else conditional operator ( `?:` ). For more information about the conditional operator, see Section 6.6. For more information about the bitwise operators, see Section 6.5.6.

### 8.1.2.1 Rules for Specifying Macro Definitions

Preprocessor directives and macro references have syntax that is independent of the C language. Follow these rules when specifying macro definitions:

- The macro name and the formal parameters are identifiers and are specified according to the rules for identifiers in the C language.
- Spaces, tabs, and comments may be used freely within a `#define` directive anywhere that the delta symbol (<ucDelta symbol>) appears in the following example:

      <ucDelta symbol>
      #<ucDelta symbol>define <ucDelta symbol>
      name(<ucDelta symbol>parm1<ucDelta symbol>,<ucDelta symbol>parm2<ucDelta symbol>)<ucDelta symbol>\

      <ucDelta symbol>token-string<ucDelta symbol>

  Spaces, tabs, and comments are replaced by a single space.
- White space cannot appear between the name and the left parenthesis that introduces the parameter list. White space may appear inside the replacement list. Also, at least one space, tab, or comment must separate name from `define` .
- The identifier __VA_ARGS__ can occur only in the replacement-list of a function-like macro that uses the ellipsis notation in the arguments.

### 8.1.2.2 Rules for Specifying Macro References

Follow these rules when specifying macro references:

- Comments and white-space characters (spaces, horizontal and vertical tabs, new-line characters, and form feeds) may be used freely within a macro reference anywhere that the delta symbol (<ucDelta symbol>) appears in the following example:

      <ucDelta symbol>name<ucDelta symbol>(<ucDelta symbol>arg1<ucDelta symbol>,<ucDelta symbol>arg2<ucDelta symbol>)

- Arguments consist of arbitrary text. Syntactically, they are not restricted to C expressions. They may contain embedded comments and white space. Comments are replaced with a single space. White space (except for leading and trailing white space) is preserved during the substitution.
- The number of arguments in the reference must match the number of parameters in the macro definition. Null arguments result in undefined behavior.
- Commas separate arguments except where the commas occur inside string or character constants, comments, or pairs of parentheses. Parentheses must be balanced within arguments.

### 8.1.2.3 Side Effects in Macro Arguments

It is not good programming practice to specify macro arguments that use the increment (++), decrement (-- --), and assignment operators (such as +=) or other arguments that can cause side effects. For example, do not pass the following argument to the `_toupper` macro:

    _toupper(p++)

When the argument `p++` is substituted in the macro definition, the effect within the program stream is as follows:

    ((p++) >= 'a' && (p++) <= 'z' ? (p++) & 0X5F : (p++))

Because `p` is being incremented, it does not have the same value for each occurrence in this macro replacement. Even if you are aware of possible side effects, the replacement lists within macro definitions can be changed, which changes the side effects without warning.

## 8.1.3 Conversions to String Literals (#)

The `#` preprocessor operator is used to convert the argument that follows it to a string literal. The preprocessor operator `#` can be used only in a function-like macro definition. For example:

    #include <stdio.h>

    #define PR(id) printf("The value of " #id " is %d\n", id)

    main()
    {
     int i = 10;

     PR(i);
    }

The output produced is:

    The value of i is 10

The macro call expands in the following steps:

    /*1*/  printf("The value of " #id " is %d\n", id)
    /*2*/  printf("The value of " "i" " is %d\n", 10)
    /*3*/  printf("The value of i is %d\n", 10)

The unary `#` operator produces a string from its operand. This example also uses the fact that adjacent string literals are concatenated. If the operand to `#` contains double quotes or escape sequences, they are also expanded. For example:

    #include <stdio.h>

    #define M(arg) printf(#arg " is %s\n", arg)

    main()
    {
     M("a\nb\tc");
    }

The macro call expands using the following steps:

    /*1*/  printf(#arg " is %s\n", arg)
    /*2*/  printf("\"a\\nb\\tc\"" " is %s\n", "a\nb\tc");
    /*3*/  printf("\"a\\nb\\tc\" is %s\n", "a\nb\tc");

## 8.1.4 Token Concatenation(##)

The `##` preprocessor operator is used to concatenate two tokens into a third valid token, as in the following example:

    #define glue(a,b) a ## b

    main()
    {
    int wholenum = 5000;

    printf("%d", glue(whole,num));
    }

The preprocessor converts the line `printf("%d", glue(whole,num));` into `printf("%d", wholenum);` , and when executed, the program prints 5000. If the result is not a valid token, an error occurs when the tokens are concatenated.

In Compaq C, the `##` operator is evaluated before any `#` operators on the line. `##` and `#` operators group left-to-right.

# 8.2 Conditional Compilation (#if, #ifdef, #ifndef, #else, #elif, #endif, and defined)

Six directives are available to control conditional compilation. They delimit blocks of program text that are compiled only if a specified condition is true. These directives can be nested. The program text within the blocks is arbitrary and may consist of preprocessor directives, C statements, and so on. The beginning of the block of program text is marked by one of three directives:

- `#if`
- `#ifdef`
- `#ifndef`

Optionally, an alternative block of text can be set aside with one of two directives:

- `#else`
- `#elif`

The end of the block or alternative block is marked by the `#endif` directive.

If the condition checked by `#if` , `#ifdef` , or `#ifndef` is true (nonzero), then all lines between the matching `#else` (or `#elif` ) and an `#endif` directive, if present, are ignored.

If the condition is false (0), then the lines between the `#if` , `#ifdef` , or `#ifndef` and an `#else` , `#elif` , or `#endif` directive are ignored.

## 8.2.1 The #if Directive

The `#if` directive has the following syntax:

`#if constant-expression newline`

This directive checks whether the constant-expression is true (nonzero). The operand must be a constant integer expression that does not contain any increment (++), decrement (-- --), `sizeof` , pointer (*), address (&), and cast operators.

Identifiers in the constant expression either are or are not macro names. There are no keywords, enumeration constants, and so on. The constant expression can also include the `defined` preprocessing operator (see Section 8.2.7).

The constant expression in an `#if` directive is subject to text replacement and can contain references to identifiers defined in previous `#define` directives. The replacement occurs before the expression is evaluated. Each preprocessing token that remains after all macro replacements have occurred is in the lexical form of a token.

If an identifier used in the expression is not currently defined, the compiler treats the identifier as though it were the constant zero.

## 8.2.2 The #ifdef Directive

The `#ifdef` directive has the following syntax:

`#ifdef identifier newline`

This directive checks whether the identifier is currently defined. Identifiers can be defined by a `#define` directive or on the command line. If such identifiers have not been subsequently undefined, they are considered currently defined.

## 8.2.3 The #ifndef Directive

The `#ifndef` directive has the following syntax:

`#ifndef identifier newline`

This directive checks to see if the identifier is not currently defined.

## 8.2.4 The #else Directive

The `#else` directive has the following syntax:

`#else newline`

This directive delimits alternative source text to be compiled if the condition tested for in the corresponding `#if` , `#ifdef` , or `#ifndef` directive is false. An `#else` directive is optional.

## 8.2.5 The #elif Directive

The `#elif` directive has the following syntax:

`#elif constant-expression newline`

The `#elif` directive performs a task similar to the combined use of the `else-if` statements in C. This directive delimits alternative source lines to be compiled if the constant expression in the corresponding `#if` , `#ifdef` , `#ifndef` , or another `#elif` directive is false and if the additional constant expression presented in the `#elif` line is true. An `#elif` directive is optional.

## 8.2.6 The #endif Directive

The `#endif` directive has the following syntax:

`#endif newline`

This directive ends the scope of the `#if` , `#ifdef` , `#ifndef` , `#else` , or `#elif` directive.

The number of necessary `#endif` directives changes according to whether the `elif` or `#else` directive is used. Consider the following equivalent examples:

    #if true                             #if true
    .                                    .
    .                                    .
    .                                    .
    #elif true                           .
    .                                    #else
    .                                    #if false
    .                                    .
    #endif                               .
                                         .
                                         #endif
                                         #endif

## 8.2.7 The defined Operator

Another way to verify that a macro is defined is to use the `defined` unary operator. The `defined` operator has one of the following forms:

`defined name`

`defined (name)`

An expression of this form evaluates to 1 if name is defined and to 0 if it is not.

The `defined` operator is especially useful for checking many macros with just a single use of the `#if` directive. In this way, you can check for macro definitions in one concise line without having to use many `#ifdef` or `#ifndef` directives.

For example, consider the following macro checks:

    #ifdef  macro1
    printf( "Hello!\n" );
    #endif

    #ifndef  macro2
    printf( "Hello!\n" );
    #endif

    #ifdef  macro3
    printf( "Hello!\n" );
    #endif

Another use of the `defined` operator is in a single `#if` directive to perform similar macro checks:

    #if  defined (macro1)  || !defined (macro2) || defined (macro3)
    printf( "Hello!\n" );
    #endif

Note that `defined` operators can be combined in any logical expression using the C logical operators. However, `defined` can only be used in the evaluated expression of an `#if` or `#elif` preprocessor directive.

# 8.3 File Inclusion (#include)

The `#include` directive inserts the contents of a specified file into the text stream delivered to the compiler. Usually, standard headers and global definitions are included in the program stream with the `#include` directive. This directive has two forms:

`#include "filename" newline`

`#include <filename> newline`

The format of filename is platform-dependent. If the filename is enclosed in quotation marks, the search for the named file begins in the directory where the file containing the `#include` directive resides. If the file is not found there, or if the file name is enclosed in angle brackets (< >), the file search follows platform-defined search rules. In general, the quoted form of `#include` is used to include files written by users, while the bracketed form is used to include standard library files.

See your platform-specific Compaq C documentation for information on the search path rules used for file inclusion.

Macro substitution is allowed within the `#include` preprocessor directive.

For example, the following two directives can be used to include a file:

    #define  macro1  "file.ext"

    #include macro1

Defined macros used in `#include` directives must evaluate to one of the two following acceptable `#include` file specifications or an error is reported:

`"filename"`

`<filename>`

An included file may itself contain `#include` directives. Although the Compaq C compiler imposes no inherent limitation on the nesting level of inclusion, the permitted depth depends on hardware and operating system restrictions.

# 8.4 Explicit Line Numbering (#line)

The compiler keeps track of information about line numbers in each file involved in the compilation, and uses the line number when issuing diagnostic messages to the terminal or, when compiling in batch mode, to a log file.

The `#line` directive can be used to alter the line numbers assigned to source code. This directive gives a new line number to the following line, which is then incremented to derive the line number for subsequent lines. The directive can also specify a new file specification for the program source file. The `#line` directive does not change the line numbers in your compilation listing, only the line numbers given in diagnostic messages sent to the terminal screen or log file. This directive is useful for referring to original source files that are preprocessed into C code.

The `#line` directive has three forms:

`#line integer-constant newline`

`#line integer-constant "filename" newline`

`#line pp-tokens newline`

In the first two forms, the compiler gives the line following a `#line` directive the number specified by the integer constant. The optional filename in quotation marks indicates the name of the source file that the compiler will provide in its diagnostic messages. If the file name is omitted, the file name used is the name of the current source file or the last file name specified in a previous `#line` directive.

In the third form, macros in the `#line` directive are expanded before it is interpreted. This allows a macro call to expand into the integer-constant, filename, or both. The resulting `#line` directive must match one of the other two forms, and is then processed as appropriate.

Previous | Next | Contents | Index

privacy and legal statement