syque.com

The Psychology of Quality and More

| Menu | Books | Share | Search | Settings |

C Style: Standards and Guidelines (contents)

CHAPTER 8 : Language Usage

PART 4 : USAGE

CHAPTER 8 : Language Usage
8.1 General principles of language usage
8.2 Using expressions
8.3 Using 'if'
8.4 Using 'while'
8.5 Using 'for'
8.6 Using 'do'
8.7 Using 'switch'
8.8 Using 'goto'
8.9 Using 'continue' and 'break'
8.10 Using 'return'
8.11 Using functions
8.12 Using '#define'
8.13 Conditional compilation
8.14 Other preprocessor commands
8.15 Summary

<--Prev page | Next page -->

 

8.12  Using '#define'

The #define statement has two clear uses, for simple replacements and for macros.

8.12.1  Constants

Constants are most typically absolute values or limits that variables may have, and are #define'd to avoid 'magic numbers' in the code. See 9.10 for further discussion.

8.12.2  Redefining symbols

It is possible to redefine the language to look like another, although this can be very confusing for other readers, and will confuse tools which must parse the code:

 

#define begin   {        /* make it look like Pascal! */
#define then
...
if ( a > b ) then
begin

 

There are occasions where redefining symbols is more acceptable, such as to clarify their usage. For example, redefining static (see 9.11) or do..while (see 8.6.2).

8.12.3  Macros

All C macros should have a health warning - There is great potential to confuse, and to err, with them.

Basic usage

The basic usage of the macro is to simplify or clarify code where using a function would be overkill:

 

#define SQUARE(a)   a * a
...
Beta = SQUARE( Alpha ) + Theta;

 

Note that the macro does not end with a semicolon as this could cause compilation errors.

Parethesizing

If parentheses are not used in the definition of macros, a number of unexpected effects can occur:

 

#define MULT(a, b)   a * b
...
c = MULT(d+e, f+g) * h;         /* This expands to d+e*f+g*h */

 

Most problems can be avoided by heavy use of parentheses, in particular parenthesizing the whole macro and each occurrence of its parameters:

 

#define MULT(a, b)  ((a) * (b))
...
c = MULT(d+e, f+g) * h;         /* This now expands to ((d+e)*(f+g))*h */

 

Parenthesizing does not, however, solve all problems, for example where the parameter appears more than once in the macro body:

 

#define ISUPPER(c)  ((c) >= 'A' && (c) <= 'Z')
...
if ( ISUPPER(getchar()) )       /* This calls getchar() twice */

 

If the macro is more than just a simple numeric replacement, then retaining its function-style parentheses, even if it has no parameters, indicates to the reader that it is more than a constant:

 

#define OPEN_DOOR()   (DoorStatus = OPEN)

 

Multiple statements

Where the macro contains multiple statements, it can cause problems:

 

#define INC_BOTH(a, b)  (a++; b++)
...
Theta = Gamma * INC_BOTH( Alpha, Beta );     /* will cause a syntax error */

-----------------------------------------------------------------------------

The expression can be maintained by using the comma operator (although see 8.2.6 for hazards):

 

#define INC_BOTH(a, b)  (a++, b++)
...
Theta = Gamma * INC_BOTH( Alpha, Beta );

 

When keywords are added, a macro cannot be used in an expression. One approach to containing this code is to use braces to make a single compound statement. This works in most, but not all cases:

 

#define SUM_IF_OVER(a, b)   \
        {                   \
            if ( a > b)     \
            Sum += a;       \
        }
...
if ( Alpha > Delta )
    SUM_IF_OVER( Alpha, Beta );     /* semicolon causes a syntax error! */
else
...

 

The ultimate solution is to turn the macro body into a one-shot do statement. This ensures that it is always treated as a single statement (although language checkers may complain about the constant in the while):

 

#define SUM_IF_OVER(a, b)
        do                  \
        {                   \
            if ( a > b )    \
            Sum += a;       \
        } while ( 0 )

 

Processing data and using flow control in macros is a point at which they become more liable to confusion and error. This type of macro should thus be used with care, if not avoided altogether.

Clever tricks

There are many clever tricks that can be performed with macros, such as using a comment to separate tokens which will be merged into a single token after the preprocessor pass:

 

#define CONCAT(a, b)   a/**/b     /* should result in 'ab' ? */

 

Most of these tricks will eventually cause problems in use, reading or porting, and it is better to completely avoid them.

Simplifying code

Macros can be used to simplify code, for example by putting in standard arguments for function calls, or simplifying common comparisons:

 

#define STR_EQUAL(a, b)    (strcmp((a), (b)) == 0)

 

This can sometimes be helpful. It can also be obscuring where it hides standard library functions or adds a significant number of new identifiers to be learned. A net benefit should always accrue from any macro usage.

 

<--Prev page | Next page -->

 

Site Menu

| Home | Top | Settings |

Quality: | Quality Toolbook | Tools of the Trade | Improvement Encyclopedia | Quality Articles | Being Creative | Being Persuasive |

And: | C Style (Book) | Stories | Articles | Bookstore | My Photos | About | Contact |

Settings: | Computer layout | Mobile layout | Small font | Medium font | Large font | Translate |

 

You can buy books here

More Kindle books:

And the big
paperback book


Look inside

 

Please help and share:

 

| Home | Top | Menu |

© Changing Works 2002-
Massive Content -- Maximum Speed