Date: Wed, 28 Dec 2011 10:57:28 +0100 From: david@westcontrol.com
To: ren_zokuken01@hotmail.com CC: gcc@gcc.gnu.org Subject: Re: FW:
a nifty feature for c preprocessor
On 28/12/2011 07:48, R A wrote:
i'm an amateur programmer that just started learning C. i like
most of the features, specially the c preprocessor that it comes
packed with. it's an extremely portable way of implementing
metaprogramming in C.
though i've always thought it lacked a single feature -- an
"evaluation" feature.
I think you have missed the point about the C pre-processor. It is
not a "metaprogramming" language - it is a simple text substitution
macro processor. It does not have any understanding of the symbols
(except for "#") in the code, nor does it support recursion - it's
pure text substitution. Your suggestion would therefore need a
complete re-design of the C pre-processor. And the result is not a
feature that people would want.
Many uses of the C pre-processor are deprecated with modern use of
C and C++. Where possible, it is usually better programming
practice to use a "static const" instead of a simple numeric
"#define", and a "static inline" function instead of a
function-like macro. With C++, even more pre-processor
functionality can be replaced by language features - templates give
you metaprogramming. There are plenty of exceptions, of course, but
in general it is better to use a feature that is part of the
language itself (C or C++) rather than the preprocessor.
It looks like you are wanting to get the compiler to pre-calculate
results rather than have them calculated at run-time. That's a
good idea - so the gcc developers have worked hard to make the
compiler do that in many cases. If your various expressions here
boil down to constants that the compiler can see, and you have at
least some optimisation enabled, then it will pre-calculate the
results.
If you have particular need of more complicated pre-processing,
then what you want is generally some sort of code generator. C has
a simple enough syntax - write code in any language you want (C
itself, or anything else) that outputs a C file. I've done that a
few times, such as for scripts to generate CRC tables.
And if you really want to use a pre-processing macro style, then
there are more powerful languages suited to that. You could use
PHP, for example - while the output of a PHP script is usually
HTML, there is no reason why it couldn't be used as a C
pre-processor.
say i have these definitions: #define MACRO_1 (x/y)*y #define
MACRO_2 sqrt(a) #define MACRO_3 calc13() .... #define MACRO_15 (a
+ b)/c
now, all throughout the codebase, whenever and whichever of
MACRO_1, or MACRO_2 (or so forth) needs to be called, they are
conveniently "indexed" by another macro expansion:
#define CONCAT(a, b) a##b #define CONCAT_VAR(a, b) CONCAT(a, b)
#define MASTER_MACRO(N) CONCAT_VAR(MACRO_, N)
now, if we use MASTER_MACRO with a "direct" value:
MASTER_MACRO(10) or #define N 10 MASTER_MACRO(10) both will
work.
but substitute this with:
#define N ((5*a)/c + (10*b)/c + ((5*a) % c + (10*b) % c)/c)
and MASTER_MACRO expands to: MACRO_((5*a)/c + (10*b)/c + ((5*a) %
c + (10*b) % c)/c)
which, of course is wrong. there are other workarounds or many
times this scheme can be avoided altogether. but it can be made
to work (elegantly) by adding an "eval" preprocessor operation:
so we redefine MASTER_MACRO this way: #define MASTER_MACRO(N)
CONCAT_VAR(MACRO_, eval(N)) which evaluates correctly.
this nifty trick (though a bit extended than what i elaborated
above) can also be used to *finally* have increments and
decrements (among others). since "eval" forces the evaluation of
an *arithmetic* expression (for now), it will force the
evaluation of an expression, then define it to itself. this will
of course trigger a redefinition flag from our beloved
preprocessor, but the defined effect would be:
#define X (((14*x)/y)/z) /* say this evaluates to simply 3 */
incrementing X, will simply be: #define X eval(eval(X) + 1) /* 1)
will be evaluated as 4 before any token substitution */ #define X
eval(eval(X) + 1) /* 2) will be evaluated as 5 before any token
substitution */
that easy.
to suppress the redef warnings, we can have another directive
like force_redef (which can only work in conjunction with eval)
#force_redef X eval(eval(X) + 1)
i'm just confused :-S... why hasn't this been suggested? i would
love to have this incorporated (even just on test builds) to gcc.
it would make my code so, so much more manageable and virtually
extensible to more platforms.
i would love to have a go at it and probably modify the gcc
preprocessor, but i since i know nothing of it's implementation
details, i don't know where to begin. i was hoping that this
being a gnu implementation, it's been heavily modularized (the
fact that gcc was heavily revised back then to use abstract
syntax trees, gimple, etc, past version 2.95 -- ???). so i can
easily "interrupt" the parsing operation (i wouldn't dare
implement a pre-preprocessing operation, being big and
redundant), then substitute the eval, then make the whole prasing
go again.
any advice for a novice? thnx.