How does a preprocessor macro work? - c

#define B 100+B
main()
{
int i= B;
}
I know it's wrong, but just out of curiosity, when I compile it I get this weird error:
"B was not declared in this scope".
Why is it so? If this error was because the compiler removes the macro after its substitution then how does the following code worked fine, when B must have been removed before it was made available to A ?
#define B 100
#define A 100+B
main()
{
int i= B;
int j =A;
}

Here's the output of the preprocessor:
gcc -E x.c
# 1 "x.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "x.c"
main()
{
int i= 100+B;
}
As you can see, it did the substituion. Now comes the compile step which fails because there's no B declared.
The other code is fine, here's the output:
main()
{
int i= 100;
int j =100+100;
}

Macro expansion isn't done recursively, if the macro name appears in the replacement text, it isn't expanded again. So with
#define B 100 + B
a replacement of B yields the token sequence 100 + B and B is not expanded again (if it were, you'd have an infinite recursion). So the compiler sees a reference to the undeclared variable B after the preprocessor finished.
But in
#define B 100
#define A 100 + B
when the macro A is expanded, the macro name B appears in the replacement text. Then B is expanded and the compiler sees 100 + 100 which contains no references to undeclared variables.

macro replacement are simple text operation.you can debug this type of problem in a simple step by step compile.
use cc -E filename.c -O filename.i
for generate extended c code
vi filename.i for reading pure/extended c code

Related

C++ preprocessor ## operator

What is wrong? I would like the xconcat line to work.
#define concat(a,b) a ## b
#define xconcat(a,b) concat(a,b)
int main() {
xconcat(xconcat(boost::variant<,int), >) y;
boost::variant<int> x;
return 0;
}
g++ -E x.cpp
# 1 "x.cpp"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "x.cpp"
int main() {
x.cpp:5:1: error: pasting "<" and "int" does not give a valid preprocessing token
x.cpp:5:1: error: pasting "int" and ">" does not give a valid preprocessing token
boost::variant<int > y;
boost::variant<int> x;
return 0;
}
The token pasting operator technically can't be used to paste something that doesn't end up being a token. GCC enforces that restriction, while some other compilers don't (the ## operator just seems to perform basic concatenation of the strings which then gets tokenized later).
From C++11 16.3.3/3 "The ## operator":
If the result is not a valid preprocessing token, the behavior is undefined.
The same language is in pretty much every C and C++ standard going back to C90.
In your case you don't need to use token pasting since you're dealing with separate tokens anyway:
#define yyconcat(a,b) a b
#define yconcat(a,b) yyconcat(a,b)
int main() {
yconcat(yconcat(boost::variant<,int), >) y;
boost::variant<int> x;
return 0;
}
g++ -E so-test.c
C:\so-test>g++ -E so-test.c
# 1 "so-test.c"
# 1 "<command-line>"
# 1 "so-test.c"
int main() {
boost::variant< int > y;
boost::variant<int> x;
return 0;
}

Why is the value of macro is not changing in a called function?

I came across a program on one C aptitude question site
#define i 20
void fun();
int main(void)
{
printf("%d..",i);
fun();
printf("%d",i);
}
void fun() {
#undef i;
#define i 30
}
Here the output comes to be
20..20
But according to me it should be
20..30
Why dosen't the value of i become 30 after call to fun()?
#define i 20
void fun();
int main(void)
{
printf("%d..",i);
#define i 50
printf("%d",i);
}
But if i compile and run above program the output comes to be 20..50
So now how macro value is changing at runtime.
Macros cannot be changed at runtime. In your program the macro is changed by the preprocessor once before compiling so it's value in the compiled program is 30.
You can read about it here.
void fun() {
#undef i;
#define i 30
}
will actually be an empty function, the preprocessed program would be
void fun();
int main(void)
{
printf("%d..",20);
fun();
printf("%d",20);
}
void fun() {
}
so you can see that the output is correct.
To generate the above preprocessed program you can use this with gcc
gcc -E -P source.c
is actually an empty function
The proprocessor's directives are completely independent and separate to program's ordinary flow. The reason for this lies in translation phases, that are specified in C Standard. The processing stage (phases 1-4) is performed conceptually before proper compilation (phase 7). The unit obtained after preprocessing stage is called as translation unit and you can think of it as "starting point" for further translation, including proper compilation.
Your compiler may allow to inspect particular translation unit, so you get how it looks effectively. For example gcc has -E flag for that (by default, it outputs so called linemarkers, but you can suppress them using -P flag). In your case it might look as:
$ gcc -E test.c
# 1 "test.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "test.c"
void fun();
int main(void)
{
printf("%d..",20);
fun();
printf("%d",20);
}
test.c:13:9: warning: extra tokens at end of #undef directive
void fun() {
}

Expanding a single C pre-processor directive

I need to expand a single preprocessor directive, for example:
Having a source file and two headers, I want to expand only one define from one specific header, leaving all other include and define intact.
The main idea is that, given code similar to this:
defs.h:
#define FOO(X,op) int X(int a,int b) { return a op b; }
other_file.h:
#define ONE 1
#define TWO 2
#define THREE 3
#define FOUR 4
#define FIVE 5
main.c:
"file: main.c "
#include <stdio.h>
#include "defs.h"
#include "other_file.h"
FOO(add,+)
FOO(sub,-)
FOO(mul,*)
FOO(div,/)
int main()
{
printf("%d\n",add(ONE,TWO));
printf("%d\n",sub(THREE,FOUR));
printf("%d\n",mul(FIVE,FIVE));
printf("%d\n",div(25,FIVE));
return 0;
}
I would have the main.c output with the same includes, but with FOO expanded to the created functions. I known the example is silly, but I intend to run it on a larger code database.
The motivation to do it is to run cccc in functions that are defined within macros. The easiest way to run it is to expand those macros. I also welcome alternative ways to do this.
You can play with the -E, -nostdinc, -nostdinc++ and -fpreprocessed parameters of GCC.
For your example, you can run:
gcc -E -nostdinc -fpreprocessed main.c
And the output would be:
# 1 "main.c"
#include <stdio.h>
#include "defs.h"
#include "other_file.h"
FOO(add,+)
FOO(sub,-)
FOO(mul,*)
FOO(div,/)
int main()
{
printf("%d\n",add(ONE,TWO));
printf("%d\n",sub(THREE,FOUR));
printf("%d\n",mul(FIVE,FIVE));
printf("%d\n",div(25,FIVE));
return 0;
}
If the headers are not that complex, like in your example, you can force gcc to preprocess the whole file even with some missing macros. E.g.:
cp other_file.h other_file.h_orig
echo "" > other_file.h
gcc -E -nostdinc main.c
Output:
# 1 "main.c"
# 1 "<command-line>"
# 1 "main.c"
main.c:1:19: error: no include path in which to search for stdio.h
#include <stdio.h>
^
# 1 "defs.h" 1
# 3 "main.c" 2
# 1 "other_file.h" 1
# 4 "main.c" 2
int add(int a,int b) { return a + b; }
int sub(int a,int b) { return a - b; }
int mul(int a,int b) { return a * b; }
int div(int a,int b) { return a / b; }
int main()
{
printf("%d\n",add(ONE,TWO));
printf("%d\n",sub(THREE,FOUR));
printf("%d\n",mul(FIVE,FIVE));
printf("%d\n",div(25,FIVE));
return 0;
}
It will remove the header inclusions, though... and will print you an error on std headers, that goes to stderr instead of stdout.
This works for your small example, but on larger codebase you may face some problems...
Here is a brief summary of the parameters from the manual (of GCC 4.8.2) :
-E: Stop after the preprocessing stage; do not run the compiler proper. The output is in the form of preprocessed source code, which
is sent to the standard output.
-fpreprocessed: Indicate to the preprocessor that the input file has already been preprocessed. This suppresses things like macro
expansion, trigraph conversion, escaped newline splicing, and
processing of most directives.
-nostdinc: Do not search the standard system directories for header files. Only the directories you have specified with -I options.
-nostdinc++: Do not search for header files in the standard directories specific to C++, but do still search the other standard
directories.
Our DMS Software Reengineering Toolkit with its C Front End will do this.
DMS provides general purpose program parsing/analysis infrastructure. The C Front End builds on that to provide a full-function C front, complete with C preprocessor.
Normally, the DMS C preprocessor acts just like the standard one: it preprocesses everything, producing a substituted stream of tokens. Unusually, it can be configured to NOT process conditionals (this is all-or-nothing), or to expand only designated macros. In particular, it accepts a custom #pragma that declares that a macro should (not) expand.
It isn't clear to me that this is worth the effort. Yes, a metrics tool might produce more accurate answers in certain places where some macro is heavily used, if you believe that the macro should be non-opaque. If you think the macro is essentially just a funny-looking subroutine, then expanding this macro is like inlining a function body, and you would not do that to compute metrics.

I don't want to preprocess specific macros. It should not replace it with its value. Is it possible?

Example =
#define a 100
#define b 200
main()
{
int c=a+b;
}
After preprocessing
Output-
#define a 100
main()
{
int c=a+200;
}
You could try refactoring the macros to allow external configuration, i.e.
/* config.h */
/* set defaults for a and b */
#ifndef a
#define a 100
#endif
#ifndef b
#define b 200
#endif
and
/* main.c */
#include "config.h"
int main(void)
{
int c = a + b;
}
Then you can set the macros externally when building, for instance like this:
$ gcc -E -Da=a main.c
# 1 "main.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "main.c"
# 1 "config.h" 1
# 4 "main.c" 2
int main(void)
{
int c = a + 200;
}
$ gcc -E -Db=b main.c
# 1 "main.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "main.c"
# 1 "config.h" 1
# 4 "main.c" 2
int main(void)
{
int c = 100 + b;
}
Now, of course you don't have to use a separate configuration header, but I'd recommend it from a maintenance perspective, it will make it easier to keep track of available configuration settings and their defaults.
#define a 100
#define b 200
main()
{
#undef b
int c=a+b;
}
No. What's your real goal?
If you want to do, it's better to make some script to do that.
If you don't want to preprocess a macro, just don't use it:
#define a 100
//#define b 200
int main()
{
int c = a + 200;
return 0;
}
The purpose of preprocessing is to process the preprocessing directives. I don't know of any way to keep a specific preprocessing directive, especially because the next step, compilation, doesn't know anything about these.
This is another reason why you should be careful when using macros -- when the name is found in the source, then it is substituted, no matter what:
#define a 100
main()
{
int a; // Compilation error happens here
....
}
Regarding Peter Miehle's answer, unifdef can be used to partially process #if and #ifdef directives, but it cannot be used to selectively expand macros. See http://dotat.at/prog/unifdef

#define f(g,g2) g##g2

#define f(g,g2) g##g2
main()
{
int var12=100;
printf("%d",f(var,12));
}
The above program prints 100 in c by concatenating var and 12. How does g##g2 work??
## just pastes tokens together. It is a preprocessor directive.
E.g.
#define PASTE(a,b) a##b
int i=PASTE(1,2); /* int i=12; */
## is the preprocessor "command" for concatenating what comes before and after.
This is token pasting, described here for gcc. Token pasting is done by the preprocessor, not the compiler.
So after preprocess it will look like this:
main()
{
int var12=100;
printf("%d",var12);
}
Concatenation is being performed by the preprocessor because you used the ## command.
When you are unsure what the preprocessor is doing you can ask gcc to stop after it has run the preprocessor. Since this is before the compiler runs, the output is fairly easy to understand.
For example, assume you have a file pre.c
#define FOO 123
#define CONCAT(x,y) x##y
#define STRING(x) #x
void main()
{
int a = FOO;
int b = CONCAT(123,4567);
char* c = STRING(IGetQuoted);
}
You can produce the preprocessor output by passing the -E option to gcc.
$ gcc -E pre.c
# 1 "pre.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "pre.c"
void main()
{
int a = 123;
int b = 1234567;
char* c = "IGetQuoted";
}
Keep in mind that #include will pull in the contents of the file it specifies and can make the preprocessor output rather long.

Resources