cgcccompiler-construction

What does #define do in the Compiler?


I've been using C for a little over a year now, and I was wondering exactly how #define works. I know you can use it as a macro, eg. #define MUL(x, y) (x*y), but what's happening when you define something without giving a definition? e.g.

    #ifndef _SYNNOVESLIB_H
    #define _SYNNOVESLIB_H
    #endif

Does it just get marked as "defined", or true (as in 1) by GCC or whatever compiler is being used?


Solution

  • #define _SYNNOVESLIB_H tells the compiler to replace _SYNNOVESLIB_H with nothing. It will be true for the purposes of things which check whether a macro is defined such as defined, #ifdef, and #ifndef.

    It can also be handy for conditionally defining certain features for compatibility. Here's an example in Perl 5.


    6.10 Preprocessing directives provides the grammar for #define.

    control-line:
      # define identifier replacement-list new-line
    
    replacement-list: 
      pp-tokens(opt)
    
    pp-tokens:
      preprocessing-token
      pp-tokens preprocessing-token
    

    replacement-list is an optional list of pre-processor tokens, so it can be empty.

    From 6.10.1 Conditional inclusion

    1. The expression that controls conditional inclusion shall be an integer constant expression except that: identifiers (including those lexically identical to keywords) are interpreted as described below;169) and it may contain unary operator expressions of the form

    defined identifier

    or

    defined ( identifier )

    which evaluate to 1 if the identifier is currently defined as a macro name (that is, if it is predefined or if it has been the subject of a #define preprocessing directive without an intervening #undef directive with the same subject identifier), 0 if it is not.

    Note that the value does not matter, simply that it has been defined.

    1. Preprocessing directives of the forms

    # ifdef identifier new-line groupopt

    or

    # ifndef identifier new-line groupopt

    check whether the identifier is or is not currently defined as a macro name. Their conditions are equivalent to #if defined identifier and #if !defined identifier respectively.

    Exactly how this is handled inside the compiler is up to the compiler, but a simple hash table would do. #define _SYNNOVESLIB_H would add a key of _SYNNOVESLIB_H with a null or empty value. #ifndef _SYNNOVESLIB_H would check whether the key exists in the hash table, ignoring the value. #undef _SYNNOVESLIB_H removes the key from the table.