How Does C++ Preprocessors Work

How C preprocessor works?

The behaviour in the first case is correct because once a macro has been used once in an expansion, it can't be used again. So, the preprocessor first turns the ABC in int ABC; into int xYz;, and then it turns the xYz back into ABC, but there are no further transforms possible because both macros have been used once.

The second code behaves correctly too, of course. The int ABC; is turned directly into int kkk;. The int xYz; is turned into int ABC; and then into int kkk;.

You can look at How many passes does the C preprocessor make? for some more information.

Does the preprocessor do macro substitution one by one, like first the expansion corresponding to #define ABC xYz is done then it goes for #define xYz ABC, or does it handle both macros in one go? If the first is the case then the output should be int ABC and int ABC.

The sequence in which the macros are defined is immaterial. The preprocessor tokenizes the input, and for each symbol, it looks to see whether there is a macro defined. If there is a macro, it applies the macro expansion and then marks it as 'used' (for the current token expansion). It then rescans the replacement text, looking for tokens again, and applying macros again (unless they're marked 'used'). The 'marking as used' prevents infinite recursion in macro expansion. When it finishes rescanning the replacement text, all the 'used' macros are marked 'unused' again.

How does C++ Preprocessors work?

The preprocessor is just a text find and replace, so in the Frame definition you showed, the preprocessor first sees DECLARE_CLASS(Frame) and replaces it with the content of the DECLARE_CLASS macro, becoming

namespace ob_instance{
class Frame: public GuiObject{
public:
Frame();
virtual ~Frame();

virtual void render();

virtual Instance* cloneImpl();
virtual QString getClassName();
virtual int wrap_lua(lua_State* L);
DECLARE_STATIC_INIT(Frame);
protected:
static QString ClassName;
static QString LuaClassName;
};
}

(I cleaned up the formatting, in reality the entire replacement text is on one line).

It then backs up to just before the text it inserted, starts reading through again, and sees DECLARE_STATIC_INIT(Frame) and replaces that:

namespace ob_instance{
class Frame: public GuiObject{
public:
Frame();
virtual ~Frame();

virtual void render();

virtual Instance* cloneImpl();
virtual QString getClassName();
virtual int wrap_lua(lua_State* L);
static void static_init_func();
static OpenBlox::static_init_helper Frame_static_init_helper;
protected:
static QString ClassName;
static QString LuaClassName;
};
}

(The ## is the token concatenation operator)

Giving you the final Frame class definition.

As mentioned by Chris Beck in the comments, you can use the -E flag to gcc or clang to have the compiler output the preprocessed file instead of compiling it.

In what situations does C preprocessor ## work and not work?

Is there a clear set of rules for using ##?

The C standard 6.10.3.1:

After the arguments for the invocation of a function-like macro have been identified,
argument substitution takes place. A parameter in the replacement list, unless preceded
by a # or ## preprocessing token or followed by a ## preprocessing token (see below), is
replaced by the corresponding argument after all macros contained therein have been
expanded.

Basically the ## concatenation happens before token expansion, because the result of ## could result in a new preprocessor token. In case we have this:

#define concat(a,b) a##b
#define BAR bar
#define fuBAR "hello world"

Then puts(concat(fu,BAR)); will print "hello world".

In order to fix this, you need a helper macro which expands the preprocessor tokens before passing them to the macro where ## (or #) resides:

#define cc(a,b) a##b
#define concat(a,b) cc(a,b)

#define BAR bar
#define fuBAR "hello world"
#define fubar "fubar"

In this example a and b are expanded to fu and bar before cc is invoked. So now puts(concat(fu,BAR)); will print "fubar".



Here ## produces an error about a stray ## in the code.

Because you can only use # and ## inside macros, simple as that. extern int fu##BAR (); is not a macro.

Working of the C Preprocessor

The preprocessor just replaces b with a wherever it finds it in the program and then replaces a with 170 It is just plain textual replacement.

Works on gcc.

How does the preprocessor work in C?

you'll get

j =16/2*2; // (16 / 2) * 2 = 16

How does C preprocessor actually work?

It's a sequencing issue. First the macros are defined, and score is undefined before it is ever used. Then, when print_score is expanded, it first substitutes all instances of student_exam_score, of which there are none. It then rescans the result, looking for further macros to expand, but there are none since score has been undefined and is no longer available.

Even if you moved #undef score down below the reference to print_score, it still wouldn't work since parameter substitution only happens once (score would be expanded but student_exam_score would not).

Note that score is not substituted into the body of print_score at the time is it defined. Substitution only happens when the macro is instantiated, which is why #undef score results in the score macro having no effect whatsoever.

These examples will make it clearer. First, consider the following:

#define foo bar
#define baz(bar) (foo)
baz(123)

This is expanded as follows:

    baz(123)
-> (foo)
-> (bar)

Expansion stops here. Parameter substitution was done before foo was expanded, and does not happen again.

Now consider the following:

#define foo bar
#define baz(bar) (foo)
#undef foo
baz(123)

This is expanded as follows:

    baz(123)
-> (foo)

Expansion stops here because foo is no longer defined. Its earlier definition had no effect on the definition of baz, because macro substitution does not happen when macros are defined. It only happens when they are expanded.

How do c/c++ preprocessors work when encountering unknown directives?

The language grammar specifies all pre-processor directives that exist in the language. If you use any other name for the directive, then that is a "conditionally-supported-directive". If the conditionally supported directive isn't supported, then the the language implementation is required to issue a diagnostic message and is free to refuse to proceed.

Trying to understand the C preprocessor

cases 1 and 2 have no defined behavior since your are tempting to paste a * into one preprocessor token. According to the association rules of your preprocessor this either tries to glue together the tokens PART1PART2 (or just PART2) and *. In your case this probably fails silently, which is one of the possible outcomes when things are undefined. The token PART1PART2 followed by * will then not be considered for macro expansion again. Stringfication then produces the result you see.

My gcc behaves differently on your examples:

/usr/bin/gcc -O0 -g -std=c89 -pedantic   -E test-prepro.c
test-prepro.c:16:1: error: pasting "PART1PART2" and "*" does not give a valid preprocessing token
"works*"

So to summarize your case 1 has two problems.

  • Pasting two tokens that don't result
    in a valid preprocessor token.
  • evaluation order of the ## operator

In case 3, your compiler is giving the wrong result. It should

  1. evaluate the arguments to
    STRINGAFY1
  2. to do that it has to expand GLUE
  3. GLUE results in PART1PART2*
  4. which must be expanded again
  5. the result is works*
  6. which then is passed to
    STRINGAFY1


Related Topics



Leave a reply



Submit