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 beint ABC
andint 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
- evaluate the arguments to
STRINGAFY1
- to do that it has to expand
GLUE
GLUE
results inPART1PART2*
- which must be expanded again
- the result is
works*
- which then is passed to
STRINGAFY1
Related Topics
Why Does 'Int ;' Compile Fine in C, But Not in C++
Lifetime of Lambda Objects in Relation to Function Pointer Conversion
How to Select a Random Element in Std::Set
Std::Vector of Std::Vectors Contiguity
What Is a Curly-Brace Enclosed List If Not an Intializer_List
Enable a Single Warning in Visual Studio
"Undefined Symbols" Linker Error with Simple Template Class
C++ Comparison of Two Double Values Not Working Properly
How to Create a Temporary Directory in C++
How to Read Bmp Pixel Values into an Array
How to Use C++ Preprocessor Stringification on Variadic MACro Arguments
How to Get the Mouse Position in a Console Program
Does C++ Contain the Entire C Language
Std::Function Fails to Distinguish Overloaded Functions
Should I Inherit from Std::Exception
Passing a Pointer Representing a 2D Array to a Function in C++