Reputation: 19477
I want to run tool x on a C file and get the post-macro code. (If we can do only function like macros even better). I know about gcc -E
but that does all the includes into one big file as well.
Basically I'd like to use some C macros for repetitive code but don't want the final code to contain any macros because they are frowned upon by the project.
Upvotes: 4
Views: 1268
Reputation: 4433
As a possible solution to your problem: "write a macro and then discard it, by replacing by an equivalent function", you can use prototyped function-like macros. They have some limitations, and must be used with some care. But they work almost the same way as a function.
#define xxPseudoPrototype(RETTYPE, MACRODATA, ARGS) typedef struct { RETTYPE xxmacro__ret__; ARGS } MACRODATA
xxPseudoPrototype(float, xxSUM_data, int x; float y; );
xxSUM_data xxsum;
#define SUM_intfloat(X, Y) ( xxsum = (xxSUM_data){ .x = (X), .y = (Y) }, \
xxsum.xxmacro__ret__ = xxsum.x + xxsum.y, \
xxsum.xxmacro__ret__)
I have explained the details here (mainly section 4, for function-like macros):
Observe that the compiler does right and transparent diagnostics of types.
(However, it is necessary to have some care with these constructs, as explained in the link).
Now, if you can collect all the sentences of your macro as a chain of function-calls separated by commas, then you can obtain function-like macro, as you desired.
Moreover, you can easily convert it into a real function, since the list of parameters is already defined. The type-checking was already done, so everything will work fine. In the example above, you have to replace all the lines (except the first), by these other ones:
#define xxPseudoPrototype(RETTYPE, MACRODATA, ARGS) typedef struct { RETTYPE xxmacro__ret__; ARGS } MACRODATA
float SUM_intfloat(int x, float y) { /* (1) */
xxPseudoPrototype(float, xxSUM_data, int x; float y; ); /* (2) */
xxSUM_data xxsum; /* (2) */
return /* (3) */
( xxsum = (xxSUM_data){ .x = x, .y = y }, /* (4) (5) (6) */
xxsum.xxmacro__ret__ = xxsum.x + xxsum.y, /* (5) (6) */
xxsum.xxmacro__ret__) /* (6) */
; /* (7) */
} /* (8) */
The replacement will follow a sistematic procedure:
(1) Macro header turned into function header. Semicolons (;) are replaced by commas (,).
(2) Declaration lines are moved inside function body.
(3) The "return" word is added.
(4) Macro arguments X, Y, are replaced by function parameters x, y.
(5) All ending "\"s are removed.
(6) All intermediante calculations and function calls are left untouched.
(7) Semicolon added.
(8) Closing function body.
Problem: Although this approach solves your needs, note that the function has duplicated its list of parameters. This is not good: pseudoprototypes and duplicates have to be erased:
float SUM_intfloat(int x, float y) {
return
( x + y )
;
}
Upvotes: 0
Reputation: 20272
I decided to add another answer, because it's entirely different.
Instead of having tricks to expand macros into the project source repository - have you considered using const
variables and inline
functions as alternative?
Basically those are the reasons that the macros are "frown upon" in your project.
You have to keep in mind that inline
is merely a "suggestion" (i.e.: the function might not be in fact inlined) and const
will use memory instead of being a constant literal (well, depends on compiler, good compiler will optimize), but that will do two things:
So keep that in mind as well, as an option.
Upvotes: 1
Reputation: 16406
Using the scripting language of your choice, comment out all #include
s, then run gcc -E -Wp,-P,-C,-CC foo.c
then uncomment the #include
s. Or you could replace #include
with some string that doesn't start with a #
... e.g., include#
or @include
; the possibilities are endless. The approach of using @
instead of #
gives you complete control over which preprocessor directives do and don't get expanded ... code the ones you don't want expanded with @
, and then the script just runs gcc -E
and then changes @
to #
. However, I think it would be better to do it the other way around, using a special marker (e.g., @
) to indicate your expandable macros. Then the script would turn leading #
s into something else (e.g., HIDE#
) and turn the marker (@
, for instance) into #
, run gcc -E
, then turn HIDE#
(or whatever) back into #
.
-Wp
specifies preprocessor options. -P
means don't generate line directives, -C
means don't delete comments, and -CC
means don't delete comments generated by macros -- that means that comments in your code-generating macros will be preserved in the output. To determine all available preprocessor options (there are a great many, mostly not of interest), run gcc -Wp,--help anyfile.c
... that's what I did to come up with this answer (after first running gcc --help
to find the -Wp
option). (Knowing how to find things out is more important than knowing things.)
Upvotes: 3
Reputation: 20272
How about putting a delimiter in your code right after the #include
list, so that you could get rid of the include files expansions manually, but have the macro expansion intact after running gcc -E
?
Something like:
#include <one>
#include <two>
void delete_everything_above_and_put_includes_back(); // delimeter
#define MACRO(X) ...
//rest of the code
I'm not aware of a tool that expands macros but doesn't expand #include
s...
Upvotes: 2