I have a number of definitions consisting of two comma-separated expressions, like this:
#define PIN_ALARM GPIOC,14
I want to pass the second expression of those definitions (14 in the case above) to unary macros like the following:
#define _PIN_MODE_OUTPUT(n) (1U << ((n) * 2U))
How can I extract the second number? I want a macro, call it "PICK_RIGHT", which will do this for me:
#define PICK_RIGHT(???) ???
So that I can make a new macro that can take my "PIN" definitions:
#define PIN_MODE_OUTPUT(???) _PIN_MODE_OUTPUT(PICK_RIGHT(???))
And I can simply do:
#define RESULT PIN_MODE_OUTPUT(PIN_ALARM)
Do not use macros for this. If you must, the following will work by throwing away the left part first so just the number remains. Use with care. No guarantees.
#define PIN_ALARM GPIOC,14
#define RIGHTPART_ONLY(a,b) b
#define PIN_MODE_OUTPUT(a) RIGHTPART_ONLY(a)
#define RESULT PIN_MODE_OUTPUT(PIN_ALARM)
int main (void)
{
printf ("we'll pick ... %d\n", PIN_MODE_OUTPUT(PIN_ALARM));
printf ("or maybe %d\n", RESULT);
return 0;
}
If you want the left part as a string, you can use this (with the same warnings as above), where the left part gets converted to a string by #:
#define LEFTPART_ONLY(a,b) #a
#define PIN_MODE_NAME(a) LEFTPART_ONLY(a)
There is a practical reason this is not entirely without problems. GPIOC is a symbol and as such it is possibly defined elsewhere. Fortunately, it is not a problem if it is undefined, or it is but to a simple type - after all, first thing the macros do is "throw away the left part". But as Jonathan Leffler comments
Note that if GPIOC maps to a macro containing commas, you're likely to get compilation errors.
Related
There were several questions here regarding variadic macros in C. These include:
How to make a variadic macro (variable number of arguments) which explains the basics, e.g., passing a variable number of arguments to functions such as printf
Is it possible to iterate over arguments in variadic macros?, which explains how to iteratively apply a macro to each of the arguments of the variadic macro.
https://github.com/swansontec/map-macro which explains how to do so on pairs
My question is related to the iteration technique. I am interested in a macro with this generalized semantics.
ITERATE(Before, Action, Between, After, Empty, ...)
that will place Before prior to all expansions, apply Action to each argument, place Between between every two consecutive applications, and will finally place the expansion of After. Moreover, if the number of argument With such a macro, it should be possible to write
// Loop elements
#define A(x) (x)
#define Befor (
#define After )
#define Between ||
#define Empty 1
// Define an OR macro
#define OR(...) ITERATE(Before, A, Between, Empty, __VA_ARGS__)
// Use it
OR() // Expands to 1
OR(a) // Expands to ((a))
OR(a,b) // Expands to ((a)||(b))
OR(a,b,c) // Expands to to ((a)||(b)||(c))
The purpose of course is not to write an OR function. A generalized functionality could be for more intricate applications. E.g., a macro for defining classes and functions, something to print the trace, etc.
I never liked the recursive REPEAT() macro idiom - it generates horrible hour long read error messages that are.. recursive, so you don't know where the error is and it's also hard to grasp how the OBSTRUCT(REPEAT_INDIRECT) () stuff works. Overall, overloading the macro on number of arguments and using an external tool (shell script or m4 preprocessor) to generate C source code is waay easier, easier to read, maintain and fix and also you can expand the macros on the tools side removing the burden of recursive expansion on C side. With that in mind, your ITERATE can be generated with existing preprocessor libraries, P99_FOR or BOOST_FOREACH comes to mind.
Also, typing shift all the time is strange - I prefer snake case. Here's a reduced example without Before and After macros with overloading the macro on number of arguments:
#define _in_ITERATE_0(f,b,e) e()
#define _in_ITERATE_1(f,b,e,_1) f(_1)
#define _in_ITERATE_2(f,b,e,_1,...) f(_1)b()_in_ITERATE_1(f,b,e,__VA_ARGS__)
#define _in_ITERATE_3(f,b,e,_1,...) f(_1)b()_in_ITERATE_2(f,b,e,__VA_ARGS__)
// or you could expand it instead of reusing previous one with same result:
#define _in_ITERATE_4(f,b,e,_1,_2,_3,_4) f(_1)b()f(_2)b()f(_3)b()f(_4)
// etc.... generate
#define _in_ITERATE_N(_0,_1,_2,_3,_4,_5,_6,_7,_8,_9,N,...) _in_ITERATE_##N
#define ITERATE(func, between, empty, ...) \
_in_ITERATE_N(0,##__VA_ARGS__,9,8,7,6,5,4,3,2,1,0)(func, between, empty, ##__VA_ARGS__)
#define _in_OR_OP(x) (x)
#define _in_OR_EMPTY() 1
#define _in_OR_BETWEEN() ||
#define OR(...) (ITERATE(_in_OR_OP, _in_OR_BETWEEN, _in_OR_EMPTY, ##__VA_ARGS__))
// Use it
OR() // Expands to (1)
OR(a) // Expands to ((a))
OR(a,b) // Expands to ((a)||(b))
OR(a,b,c) // Expands to to ((a)||(b)||(c))
outputs:
(1)
((a))
((a)||(b))
((a)||(b)||(c))
For more examples on overloading macro on count of arguments see this thread. I am using ## GNU extension to remove the comma before __VA_ARGS__ because I am used to using it - I think __VA_OPT__(,) should be nowadays preferred, I am not sure.
cpp_magic extends what can typically be done with the C Preprocessor.
(It's a single header file and is on GitHub, here.)
The IF_ELSE(cond)(<true_result>, <false_result>) is a super useful macro!
How can expressions be evaluated in the cond clause?
It doesn't appear to work as advertised: with expressions in the cond part.
The following returns 10:
int greater = IF_ELSE(10 > 20)(10, 20);
The macro always returns the first argument, unless it is a simple 0 or 1.
Is the c argument (condition) a misnomer (and is really ust a simple value)?
I also tried this, according to a suggestion below, but it gives the same result:
#define GREATER(x,y) BOOL(x > y)
int greater = IF_ELSE(GREATER(10,20))(10, 20);
But it also evaluates to 10.
(Note that IF_ELSE already calls BOOL(c) on its argument.)
Has anyone used IF_ELSE with a general preprocessor expression?
Looking at cpp_magic, it looks a bit basic. If you want to evaluate math in the preprocessor using that, you have to basically implement the math yourself using macros. First off the bat, cpp_magic's IF_ELSE macro is defined as follows:
#define IF_ELSE(condition) _IF_ ## condition
That's a dead stop to using it as you prescribe, because this macro's expansion list contains a paste. The way macros expand involves four steps:
Argument substitution (a.s.; 6.10.3.1), where for each mention of a parameter in the macro's replacement list where said parameter is not participating in a paste or stringification, the corresponding argument is fully expanded, and the resulting expansion replaces the mention in the replacement list.
Stringification (6.10.3.2)
Pasting (6.10.3.3)
Rescan-and-further-replacement (r.a.s.r.; 6.10.3.4), where the resulting replacement list is rescanned; during this rescan the macro in question is marked as invalid for further expansion ("painted blue") to avoid recursion.
So in cpp_magic's implementation of IF_ELSE, no matter what you pass in as the condition, it will not do a.s.; instead, it will simply paste to _IF_. E.g., if you call IF_ELSE(BOOL(x)), you would simply get _IF_BOOL(x). You can patch this (but it's ugly, and there's a much much better library... see below) by adding an indirection macro like this:
#define EVAL_IF_ELSE(condition) IF_ELSE(condition)
...so you need at least this. For a greater comparision, you would need to implement greater. Here's a trivial implementation:
#define GLUE(A,B) GLUE_I(A,B)
#define GLUE_I(A,B) A##B
// repeats X N times
#define N_TIMES(N,X) GLUE(N_TIMES_,N)(X)
#define N_TIMES_1(X) X
#define N_TIMES_2(X) X,N_TIMES_1(X)
#define N_TIMES_3(X) X,N_TIMES_2(X)
#define N_TIMES_4(X) X,N_TIMES_3(X)
#define N_TIMES_5(X) X,N_TIMES_4(X)
// pop; technically non-compliant for one parameter
// which I could code around, but this is a simplified
// demo only (and there's a much better way)
#define POP(...) POP_I(__VA_ARGS__)
#define POP_I(X,...) __VA_ARGS__
#define NTH(N,...) GLUE(NTH_,N)(__VA_ARGS__)
#define NTH_1(...) NTH_1_I(__VA_ARGS__,)
#define NTH_1_I(X,...) X
#define NTH_2(X,...) NTH_1(__VA_ARGS__)
#define NTH_3(X,...) NTH_2(__VA_ARGS__)
#define NTH_4(X,...) NTH_3(__VA_ARGS__)
#define NTH_5(X,...) NTH_4(__VA_ARGS__)
#define COMPARE(X,Y) NTH(X,POP(N_TIMES(Y,L)),E,N_TIMES(5,G))
#define GREATER(X,Y) GLUE(GREATER_RESULT_,COMPARE(X,Y))
#define GREATER_RESULT_L 0
#define GREATER_RESULT_E 0
#define GREATER_RESULT_G 1
...so that's a nice start. And this greater works perfectly... for numbers up to 5... so long as you ignore the 1 case. There's a skeleton here for how to do other comparisons, but they would only work up to 5. A demo working up to 20 is shown here.
This shows what you want to do is possible, but it's still a lot of work. Here I'm only showing a way to do a comparison; but everything else you want to do (add, sub, mul, div, etc) also needs an implementation, and each piece is code. If you want to play with it, knock yourself out, but I would recommend for play ditching the C language and just use your preprocessor like I do in the demo.
There is a much, much better way
...and that is to let someone else do all of the work for you. And they have! What you're in effect trying to do has been pulled into the boost preprocessor library. BPP also has add, sub, mul, div, and so on. For BPP's implementation, the saturation is at 255. Here's how you would do your conditional using boost preprocessor:
#include <boost/preprocessor/comparison.hpp>
#include <boost/preprocessor/control.hpp>
BOOST_PP_IF(BOOST_PP_GREATER(10,20),10,20)
...and a demo
Below I change the value of the function that I call depending on the value of INPUT:
#include <stdio.h>
#define INPUT second
#if INPUT == first
#define FUNCTOCALL(X) first(X)
#elif INPUT == second
#define FUNCTOCALL(X) second(X)
#endif
void first(int x) {
printf("first %d\n", x);
}
void second(int x) {
printf("second %d\n", x);
}
int main() {
FUNCTOCALL(3);
return 0;
}
However, the output is first 3, even if INPUT is equal to second, as above. In fact, the first branch is always entered, regardless of the value of INPUT. I'm completely stumped by this - could someone explain what stupid mistake I'm making?
The c preprocessor only works on integer constant expressions in its conditionals.
If you give it tokens it can't expand (such as first or second where first and second aren't macros)
it'll treat them as 0 and 0 == 0 was true last time I used math. That's why the first branch is always taken.
6.10.1p4:
... After all replacements due to macro expansion and the defined
unary operator have been performed, all remaining identifiers
(including those lexically identical to keywords) are replaced with
the pp-number 0, and then each preprocessing token is converted into a
token. ...
You have no macros first and second defined. Be aware that the pre-processor is not aware of C or C++ function names!* In comparisons and calculations (e. g. #if value or #if 2*X == Y), macros not defined (not defined at all or undefined again) or defined without value evaluate to 0. So, as first and second are not defined, INPUT is defined without value, and the comparison in both #if expressions evaluates to 0 == 0...
However, if you did define the two macros as needed, they would collide with the C function names and the pre-processor would replace these with the macro values as you just defined them, most likely resulting in invalid code (e. g. functions named 1 and 2)...
You might try this instead:
#define INPUT SECOND
#define FIRST 1
#define SECOND 2
#if INPUT == FIRST
#define FUNCTOCALL(X) first(X)
#elif INPUT == SECOND
#define FUNCTOCALL(X) second(X)
#else
# error INPUT not defined
#endif
Note the difference in case, making the macro and the function name differ.
* To be more precise, the pre-processor is not aware of any C or C++ tokens, so it does not know about types like int, double, structs or classes, ... – all it knows is what you make it explicitly aware of with #define, everything else is just text it operates on and, if encountering some known text nodes, replacing them with whatever you defined.
How are the definitions in C processed? Are they processed in order of line numbers?
For example, will the following statements work?
#define ONE 1
#define TWO (ONE+1)
Could there be any problems with definitions that depend on previous definitions?
Yes, one #define can reference other #define substitutions and macros without any problem.
Moreover, the expression on these constants would remain a constant expression.
Your second expression would be textually equivalent to (ONE+1) replacement in the text, with no limits to the level of nesting. In other words, if you later define
#define THREE (TWO+1)
and then use it in an assignment i = THREE, you would get
i = ((ONE+1)+1)
after preprocessing.
If you are planning to use this trick with numeric values, a common alternative would be to use an enum with specific values, i.e.
enum {
ONE = 1
, TWO = ONE+1
, THREE = TWO+1
, ... // and so on
};
They're processed at point when they're used, so you example and even this
#define TWO (ONE+1)
#define ONE 1
will work.
The best way is to check by yourself:
g++ test.cpp
gcc test.c
For strict compiler check:
gcc test.c -pedantic
And all worked for me!
test.c/test.cpp
#include <stdio.h>
#define A 9
#define B A
int main()
{
printf("%d\n",B);
return 0;
}
The compiler processes the #define-s in the order they were de...fined. After each #define gets processed, the preprocessor then proceeds to process all text after this #define, using it in the state left by this #define. So, in your example:
#define ONE 1
#define TWO (ONE+1)
It first processes #define ONE 1, replacing all further occurunces of ONE with 1. So, the second macro becomes
#define TWO (1+1)
That is how it will be processed and applied by the preprocessor.
The reverse example:
#define TWO (ONE+1)
#define ONE 1
will also work. Why? Well, the preprocessor will take the first #define, scan the code for any occurences of TWO, and replace it with (ONE+1). Then it reaches the second #define, and replaces all occurences of ONE, including those put in place by the previous #define, with 1.
I'd personally prefer the former approach over the latter: it's plainly easier for the preprocessor to handle.
Let's say I have already defined 9 macros from
ABC_1 to ABC_9
If there is another macro XYZ(num) whose objective is to call one of the ABC_{i} based on the value of num, what is a good way to do this? i.e. XYZ(num) should call/return ABC_num.
This is what the concatenation operator ## is for:
#define XYZ(num) ABC_ ## num
Arguments to macros that use concatenation (and are used with the operator) are evaluated differently, however (they aren't evaluated before being used with ##, to allow name-pasting, only in the rescan pass), so if the number is stored in a second macro (or the result of any kind of expansion, rather than a plain literal) you'll need another layer of evaluation:
#define XYZ(num) XYZ_(num)
#define XYZ_(num) ABC_ ## num
In the comments you say that num should be a variable, not a constant. The preprocessor builds compile-time expressions, not dynamic ones, so a macro isn't really going to be very useful here.
If you really wanted XYZ to have a macro definition, you could use something like this:
#define XYZ(num) ((int[]){ \
0, ABC_1, ABC_2, ABC_3, ABC_4, ABC_5, ABC_6, ABC_7, ABC_8, ABC_9 \
}[num])
Assuming ABC_{i} are defined as int values (at any rate they must all be the same type - this applies to any method of dynamically selecting one of them), this selects one with a dynamic num by building a temporary array and selecting from it.
This has no obvious advantages over a completely non-macro solution, though. (Even if you wanted to use macro metaprogramming to generate the list of names, you could still do that in a function or array definition.)
Yes, that's possible, using concatenation. For example:
#define FOO(x, y) BAR ##x(y)
#define BAR1(y) "hello " #y
#define BAR2(y) int y()
#define BAR3(y) return y
FOO(2, main)
{
puts(FOO(1, world));
FOO(3, 0);
}
This becomes:
int main()
{
puts("hello " "world");
return 0;
}