KnowledgeBase Archive

An Archive of Early Microsoft KnowledgeBase Articles

View on GitHub

Q50341: Preprocessor Condenses Multi-Line Macro Invocations

Article: Q50341
Product(s): See article
Version(s): 5.00 5.10 | 5.10
Operating System(s): MS-DOS | OS/2
Keyword(s): ENDUSER | | mspl13_c
Last Modified: 17-JUL-1990

The preprocessor of the Microsoft C Optimizing Compiler versions 5.00
and 5.10 does not preserve the source code structure of macro
invocations upon expansion. Preprocessor macro expansion is carried
out on one line at a time, in a left to right fashion, until the
end-of-line is reached. Thus, when multiple-line macro invocations are
expanded, they are converted into a single line of code.

The following example defines a simple macro and displays this
conversion of multi-line macro invocations:

#define macro( arg1, arg2, arg3 ) arg1 + arg2 + arg3

     Source Code           Preprocessor Listing
    _____________          ____________________

  value = macro ( param1,  value = macro( param1 + param2 + param3 );
                  param2,
                  param3 );

Note that the preprocessor listing replaces the three lines of code
in the source file with only one line. As a result, the line numbers
between the two files are different because the preprocessor does not
perform any line number adjustment.

This may cause problems if one must compile preprocessor listings to
avoid errors generated by .C source files (i.e., insufficient heap
space). When the preprocessor listing is compiled, the subtle side
effect becomes more obvious in the form of discrepancies between
original source-code line numbers and line numbers associated with
compiler errors or debugger maps. This result can make debugging
original source code difficult and can be a general nuisance when
trying to locate erroneous lines in source code indicated by the
compiler.

The #line directive and the __LINE__ predefined macro can be used to
redefine preprocessor listing line numbers and eliminate such
differences. To compensate for the preprocessor single-line expansion
of macro invocations, place the directive "#line __LINE__" in the
source code line following the macro invocation.

The #line directive, which accepts an integer constant as an argument,
instructs the preprocessor to change the compiler's internally stored
line number to the integer argument specified. The __LINE__ macro,
which is supplied as the argument to the #line directive, evaluates to
the current line number generated during preprocessing. Working
together, they force the compiler to generate consistent line numbers
between the the source file and the preprocessor listing.

The program below illustrates the macro expansion behavior of the C
preprocessor and how it can be modified to generate
line-number-compatible source and preprocessor listings.

          /* TEST.C */           |          /* TEST.I */
                                 |
/*1*/  #define sum( a,b,c) a+b+c | /*1*/  #define sum(a,b,c) a+b+c
/*2*/                            | /*2*/
/*3*/  void main( void )         | /*3*/    void main( void )
/*4*/  {                         | /*4*/    {
/*5*/     int i;                 | /*5*/   int i;
/*6*/     i =  sum( 1,           | /*6*/   i =  sum( 1, 2, 3 );
/*7*/           2,               | /*7*/   /*  #line __LINE__    */
/*8*/           3 );             | /*8*/   i = 100000;
/*9*/     /*  #line __LINE__  */ | /*9*/    }
/*10*/    i = 100000;            | /*10*/
/*11*/ }                         | /*11*/
                                 |

When the program, TEST.C, above is compiled under warning level three,
a data conversion warning is generated for line 10, indicating
overflow of the integer variable i. TEST.C is then run through the
preprocessor using the /P compiler option, where TEST.I (above) is
generated. Compiling TEST.I under warning level three generates the
same data conversion warning, but on line 8. The line number
difference between TEST.C and TEST.I is quite obvious.

By uncommenting line 9 in the TEST.C, both the source file and
preprocessor listing contain consistent line numbers following the
macro invocation because the line number is reset to the proper value
(seven) after the preprocessor pass.

THE INFORMATION PROVIDED IN THE MICROSOFT KNOWLEDGE BASE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. MICROSOFT DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR IMPLIED, INCLUDING THE WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL MICROSOFT CORPORATION OR ITS SUPPLIERS BE LIABLE FOR ANY DAMAGES WHATSOEVER INCLUDING DIRECT, INDIRECT, INCIDENTAL, CONSEQUENTIAL, LOSS OF BUSINESS PROFITS OR SPECIAL DAMAGES, EVEN IF MICROSOFT CORPORATION OR ITS SUPPLIERS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. SOME STATES DO NOT ALLOW THE EXCLUSION OR LIMITATION OF LIABILITY FOR CONSEQUENTIAL OR INCIDENTAL DAMAGES SO THE FOREGOING LIMITATION MAY NOT APPLY.

Copyright Microsoft Corporation 1986-2002.