Seeing expanded C macros
CC PreprocessorC Problem Overview
If I want to expand a C macro, what are some good ways to do that (besides tracing it manually)?
For instance, GTK_WIDGET_SET_FLAGS
, it uses a macro that uses a macro that uses a macro (or two) ...
I want to just see it somehow expanded automagically, instead of searching for every macro, every step of the way.
UPDATE
I tried cpp, but it seemed to only do the first pass
on:
GTK_WIDGET_SET_FLAGS(obj, 13)
I got the include file expanded, and then:
G_STMT_START{ ((GTK_OBJECT_FLAGS (obj)) |= (13)); }G_STMT_END
This is explained by these error message I get this on stderr (when using -o filename)
gtk/gtkwidget.h:34:21: gdk/gdk.h: No such file or directory gtk/gtkwidget.h:35:31: gtk/gtkaccelgroup.h: No such file or directory gtk/gtkwidget.h:36:27: gtk/gtkobject.h: No such file or directory gtk/gtkwidget.h:37:31: gtk/gtkadjustment.h: No such file or directory gtk/gtkwidget.h:38:26: gtk/gtkstyle.h: No such file or directory gtk/gtkwidget.h:39:29: gtk/gtksettings.h: No such file or directory gtk/gtkwidget.h:40:21: atk/atk.h: No such file or directory
the gtk, atk, and gdk directories are all in the current working directory, so how do I let cpp search in it?
btw, gcc -E
gives the exact same output as cpp
Update2:
The include path problem is solved by using gcc -E and passing the include directory with the -I option
C Solutions
Solution 1 - C
Depending on which compiler you use, there should be a way to see the code after the preprocessor (which does the macro expansion, macros are not known by the compiler at all) is done.
With gcc, the option is -E. Here's a simplified example, using toy code and not the actual GTK+ macro:
~/tmp> cat cpptest.c
#define SET_FLAGS(w, f) ((w)->flags |= (f))
int main(void)
{
SET_FLAGS(0, 4711);
return 0;
}
~/tmp> gcc -E cpptest.c
# 1 "cpptest.c"
# 1 "<built-in>"
# 1 "<command line>"
# 1 "cpptest.c"
int main(void)
{
((0)->flags |= (4711));
return 0;
}
Solution 2 - C
In Visual Studio, you can generate the preprocessor resulted translation unit file. You can go project options, C/C++/Preprocessor and put "Generate Preprocessed File" or "Preprocess to a File" on Yes (or use /P or /EP compiler switch to include line numbers or not).
Solution 3 - C
You can dump the expansion of a macro at run time like this:
#include <stdio.h>
/*
* generic helper macros
*/
#define CALL(macro, arguments) macro arguments
#define STR(...) STR_(__VA_ARGS__)
#define STR_(...) # __VA_ARGS__
/*
* dumps a macro and its expansion to stdout
* the second argument is optional and specifies the number of
* arguments that macro takes: 0 means macro takes zero arguments
* no second argument means macro is not function-like
*/
#define DUMP_MACRO(macro, ...) \
do { \
puts ( \
"'" \
# macro STR(DUMP_MACRO_ARGS_ ## __VA_ARGS__) \
"' expands to '" \
STR(CALL(macro, DUMP_MACRO_ARGS_ ## __VA_ARGS__)) \
"'" \
); \
} while (0)
/* helpers for DUMP_MACRO, add more if required */
#define DUMP_MACRO_ARGS_
#define DUMP_MACRO_ARGS_0 ()
#define DUMP_MACRO_ARGS_1 (<1>)
#define DUMP_MACRO_ARGS_2 (<1>, <2>)
#define DUMP_MACRO_ARGS_3 (<1>, <2>, <3>)
/*
* macros to be used in examples for DUMP_MACRO
*/
#define EXAMPLE ( EXAMPLE0() << 9 )
#define EXAMPLE0() __GNUC__
#define EXAMPLE1(EXAMPLE1) EXAMPLE1
#define EXAMPLE3(EXAMPLE1, _, __) ( EXAMPLE1 ? _(__) : false )
int main() {
/* examples */
DUMP_MACRO(EXAMPLE);
DUMP_MACRO(EXAMPLE0, 0);
DUMP_MACRO(EXAMPLE1, 1);
DUMP_MACRO(EXAMPLE3, 3);
DUMP_MACRO(EXAMPLE3(EXAMPLE, EXAMPLE1, non_macro_symbol));
/* does not work for DUMP_MACRO itself, because the
preprocessor does not allow recursion */
DUMP_MACRO(DUMP_MACRO, 1);
DUMP_MACRO(DUMP_MACRO, 2);
return 0;
}
The program prints:
'EXAMPLE' expands to '( 4 << 9 )'
'EXAMPLE0()' expands to '4'
'EXAMPLE1(<1>)' expands to '<1>'
'EXAMPLE3(<1>, <2>, <3>)' expands to '( <1> ? <2>(<3>) : false )'
'EXAMPLE3(EXAMPLE, EXAMPLE1, non_macro_symbol)' expands to '( ( 4 << 9 ) ? non_macro_symbol : false )'
'DUMP_MACRO(<1>)' expands to 'DUMP_MACRO (<1>)'
'DUMP_MACRO(<1>, <2>)' expands to 'DUMP_MACRO (<1>, <2>)'
However this yields only the full expansion. If you need single steps, Eclipse/CDT can help, but only if you teach it all the headers and compiler flags you use.
Solution 4 - C
gcc -E myfile.c
Solution 5 - C
gcc even with -E needs the path of the header files ... like -I _path_to_your_headers...
If you've a Makefile, generally, what you could do is over-riding CC with gcc -E
Generally, cpp is only a script adding some flags to gcc for the preprocessor, like traditional...
Solution 6 - C
Many IDEs will show you the expanded version of the macro in the editor when the mouse pointer hovers over the identifier (or some other way). I know Eclipse/CDT does this, and Visual Studio does this (at least VS 2008 does).
Having the compiler generate preprocessed output can be useful if you're tracking down a tricky problem, but for day in/day out use where you just want to know what's going on with the code on your screen,using the IDE is the way to go.
Solution 7 - C
GCC -save-temps
The big advantage of this option over -E
is that it is very easy to add it to any build script, without interfering much in the build itself.
When you do:
gcc -save-temps -c -o main.o main.c
main.c
#define INC 1
int myfunc(int i) {
return i + INC;
}
and now, besides the normal output main.o
, the current working directory also contains the following files:
-
main.i
is a contains the desired preprossessed file:# 1 "main.c" # 1 "<built-in>" # 1 "<command-line>" # 31 "<command-line>" # 1 "/usr/include/stdc-predef.h" 1 3 4 # 32 "<command-line>" 2 # 1 "main.c" int myfunc(int i) { return i + 1; }
-
main.s
is a bonus, and contains the desired generated assembly:.file "main.c" .text .globl myfunc .type myfunc, @function myfunc: .LFB0: .cfi_startproc pushq %rbp .cfi_def_cfa_offset 16 .cfi_offset 6, -16 movq %rsp, %rbp .cfi_def_cfa_register 6 movl %edi, -4(%rbp) movl -4(%rbp), %eax addl $1, %eax popq %rbp .cfi_def_cfa 7, 8 ret .cfi_endproc .LFE0: .size myfunc, .-myfunc .ident "GCC: (Ubuntu 8.3.0-6ubuntu1) 8.3.0" .section .note.GNU-stack,"",@progbits
If you want to do it for a large number of files, consider using instead:
-save-temps=obj
which saves the intermediate files to the same directory as the -o
object output instead of the current working directory, thus avoiding potential basename conflicts.
Another cool thing about this option is if you add -v
:
gcc -save-temps -c -o main.o -v main.c
it actually shows the explicit files being used instead of ugly temporaries under /tmp
, so it is easy to know exactly what is going on, which includes the preprocessing / compilation / assembly steps:
/usr/lib/gcc/x86_64-linux-gnu/8/cc1 -E -quiet -v -imultiarch x86_64-linux-gnu main.c -mtune=generic -march=x86-64 -fpch-preprocess -fstack-protector-strong -Wformat -Wformat-security -o main.i
/usr/lib/gcc/x86_64-linux-gnu/8/cc1 -fpreprocessed main.i -quiet -dumpbase main.c -mtune=generic -march=x86-64 -auxbase-strip main.o -version -fstack-protector-strong -Wformat -Wformat-security -o main.s
as -v --64 -o main.o main.s
Tested in Ubuntu 19.04 amd64, GCC 8.3.0.
Solution 8 - C
If you use gcc you can also run
cpp myfile.c
Solution 9 - C
You want to run just the preprocessor stage of your compiler, responsible for expanding macros. For gcc
, that's "gcc -E", but I'm not sure about other compilers.
Solution 10 - C
Try running cpp on your source file
Solution 11 - C
Have you tried running gcc -E multiple times until there are no longer any macros?
Solution 12 - C
When trapped in a sketchy IDE, try something like
#define DISPLAY_VALUE2(x) #x
#define DISPLAY_VALUE(x) DISPLAY_VALUE2(x)
#pragma message("#DEFINE F_CPU " DISPLAY_VALUE(F_CPU))
to produce
…/sketch_may21a.ino: In function 'void loop()':
…/sketch_may21a.ino:10:54: note: #pragma message: #DEFINE F_CPU 16000000L
#pragma message("#DEFINE F_CPU " DISPLAY_VALUE(F_CPU))
^
thanks to "mdematos" at http://MicroChip.com/forums/m724722.aspx
Solution 13 - C
Naive Approach
Basically here's my stringification macro:
#define stringify(exp) #exp
#
is a preprocessor operator that makes strings in simple words, so
stringify(foo)
would give you "foo"
.
Problem
But if you used it on another macro like this #define FOO some_expression
, it would just expand into "FOO"
(the name of that macro) since it's not expanded yet.
Solution
This is why I have special macro that expands it first and then puts it through that special macro:
#define stringify_m(macro) stringify(macro)
Example
Now if we take this slightly more complex macro:
#define _padding_(size, id) char _padding##id##_ [((size) + sizeof(char) - 1) / sizeof(char)]
and put through stringify_m
like this:
stringify_m(_padding_(8, 6502))
the result would be:
"char _padding6502_ [((8) + sizeof(char) - 1) / sizeof(char)]"