save expanded macro result before it is undefined - c

With GCC, I am using X-macros for a collection of variables.
#define TEST_MAP \
X(0, 1, 2) \
X(0, 2, 2) \
X(0, 3, 5)
Let's suppose I need to sum up all the 2nd fields
#define X(a,b,c) (+b) /* sum all 2nd elements of TEST_MAP */
uint16_t d = (TEST_MAP);
#undef X
That works fine, because TEST_MAP is expanded as
uint16_t d = ((+1) (+2) (+3));
However, I'd prefer to use a compile-time constant, but if I do
#define X(a,b,c) (+b) /* sum all 2nd elements of TEST_MAP */
#define D (TEST_MAP)
#undef X
uint16_t d = D;
of course it won't work because at the time D is expanded X is not defined anymore, so I have:
uint16_t d = (X(0, 1, 2) X(0, 2, 2) X(0, 3, 5));
I have checked the use of # and ## but I haven't found yet how to solve this. How can I force #define D to expand to ((+1) (+2) (+3)) ?

Use enumeration:
#define X(a,b,c) (+b) /* sum all 2nd elements of TEST_MAP */
enum { D = (TEST_MAP) };
#undef X

You could rewrite your X macro so that X is a parameter to your macro:
#define TEST_MAP(X) \
X(0, 1, 2) \
X(0, 2, 2) \
X(0, 3, 5)
You can then pass the appropriate macro (which must take three arguments) without having to repeatedly #define and #undef X:
#define COL1(a, b, c) + (a)
#define COL2(a, b, c) + (b)
#define COL3(a, b, c) + (c)
#define SUM(a, b, c) + (a) + (b) + (c)
#define D1 (TEST_MAP(COL1));
#define D2 (TEST_MAP(COL2));
#define D3 (TEST_MAP(COL3));
#define S (TEST_MAP(SUM));

You are not able to expand the macro as you want because you undefine the the X macro before the point where you apply it:
#define X(a,b,c) (+b) /* sum all 2nd elements of TEST_MAP */
#define D (TEST_MAP)
#undef X //You undefine X here before usage
uint16_t d = D; //Here X doesn't exist anymore and can't expand.
Consider that the preprocessor performs expansion when encounters the macro, at that time all submacros have to be defined.
To use the macros the way you requested you have simply to undefine macro X after usage.
See the sample:
#include <stdio.h>
#define TEST_MAP \
X(0, 1, 2) \
X(0, 2, 2) \
X(0, 3, 5)
#define D (TEST_MAP)
#define X(a,b,c) +(b) /* sum all 2nd elements of TEST_MAP */
int d = (TEST_MAP);
#undef X
int main(void)
{
#define X(a,b,c) +(b) /* sum all 2nd elements of TEST_MAP */
printf("Sum of 2nd -> %d - %d\n", d, D);
#undef X
#define X(a,b,c) +(c) /* sum all 3rd elements of TEST_MAP */
printf("Sum of 3rd -> %d\n", D);
#undef X
return 0;
}
Or you can simply revert the order of preprocessor commands:
#undef X
#define X(a,b,c) +(b) /* sum all 2nd elements of TEST_MAP */
In this case the last assignement is on up to a new undefine/redefine...

Related

How to map #define's replacement list containing space(s) to integers (IDs)?

A #define's replacement list containing no spaces can be mapped to integers (IDs):
#define ID_double 1
#define ID_float 2
#define ID_long_double 3
#define ID_(x) ID_##x
#define ID(x) ID_(x)
#define T double
T v;
int x = ID(T); /* 1 */
Now consider:
#define T long double
The code above won't compile:
<source>:3:25: error: 'ID_long' undeclared here (not in a function)
Question: is there a way to support spaces?
For example (somehow):
#define REPLACE_SPACES_TO_UNDERSCORES(x) ??
#define ID(x) ID_(REPLACE_SPACES_TO_UNDERSCORES(x))
#define T long double
T v;
int x = ID(T); /* 3 */
The same idea I had in Replace spaces with underscores in a macro? can also be used here, and the dictionary will be much more realistical in size. In the following code on the end, ID(T) is replaced by 3.
// dictionary
#define WORD_long long,
#define WORD_double double,
// ---------------------------------------------
// the classics
#define COMMA(...) ,
#define FIRST(a, ...) a
// apply function f for each argument recursively with tail
#define FOREACHTAIL_1(f,a) f(a,)
#define FOREACHTAIL_2(f,a,...) f(a,FOREACHTAIL_1(f,__VA_ARGS__))
#define FOREACHTAIL_3(f,a,...) f(a,FOREACHTAIL_2(f,__VA_ARGS__))
#define FOREACHTAIL_4(f,a,...) f(a,FOREACHTAIL_3(f,__VA_ARGS__))
#define FOREACHTAIL_N(_4,_3,_2,_1,N,...) \
FOREACHTAIL_##N
#define FOREACHTAIL(f,...) \
FOREACHTAIL_N(__VA_ARGS__,4,3,2,1)(f,__VA_ARGS__)
// if there are two arguments, expand to true. Otherwise false.
#define IFTWO_N(_0,_1,N,...) N
#define IFTWO(true, false, ...) IFTWO_N(__VA_ARGS__, true, false)
// If empty, expand to true, otherwise false.
// https://gustedt.wordpress.com/2010/06/08/detect-empty-macro-arguments/
#define IFEMPTY(true, false, ...) IFTWO(true, false, COMMA __VA_ARGS__ ())
// Join arguments with `_`.
#define JOIN_U(a, b) a##_##b
#define JOIN_TWO_IN(a,b) IFEMPTY(FIRST, JOIN_U, b)(a, b)
#define JOIN_TWO(a,b) JOIN_TWO_IN(a,b)
#define JOIN(...) FOREACHTAIL(JOIN_TWO, __VA_ARGS__)
// Append WORD_ to each argument and join arguments with spaces.
#define WORD_ /* the last one expands to empty */
#define WORDS_TWO(a, b) WORD_##a b
#define WORDS(...) FOREACHTAIL(WORDS_TWO, __VA_ARGS__)
#define REPLACE_SPACES_TO_UNDERSCORES(a) JOIN(WORDS(WORDS(WORDS(WORDS(WORDS(a))))))
// --------------------------------------------
#define ID_double 1
#define ID_float 2
#define ID_long_double 3
#define ID_IN2(x) ID_##x
#define ID_IN(x) ID_IN2(x)
#define ID(x) ID_IN(REPLACE_SPACES_TO_UNDERSCORES(x))
int main() {
#define T long double
T v;
int x = ID(T); /* 3 */
}

Using C defines to simplify constant definitions?

I have the following defines:
#define M(x) ( ((uint64_t) 1) << (x) )
#define Mx M(0)
#define My M(1)
#define Mz M(2)
Quite often I need to rearrange the order of Mx, My, Mz, for example:
#define My M(0)
#define Mz M(1)
#define Mx M(2)
How would I make this more generic in a sense of not having to correct M(0/1/2) every time, but just shuffle the lines?
#define POS ...
#define My M(POS)
#define Mz M(POS)
#define Mx M(POS)
You could use an extra macro in between that will select an appropriate argument from the permutation. The permutation would be a macro itself that can be undefined and redefined.
#define NTH0(a0,a1,a2) a0
#define NTH1(a0,a1,a2) a1
#define NTH2(a0,a1,a2) a2
#define NTH(n, perm) NTH ## n (perm)
#define Mx M(NTH(0, PERM))
#define My M(NTH(1, PERM))
#define Mz M(NTH(2, PERM))
#define PERM 1,2,3
Mx
My
Mz
#undef PERM
#define PERM 3,2,1
Mx
My
Mz
When compiled with gcc -E it expands to:
M(1)
M(2)
M(3)
M(3)
M(2)
M(1)
The best solution might be to solve this with version control or #ifdef switches rather than function-like macros. Or perhaps generate the C source through a script.
Otherwise, the standard pre-processor way to list stuff while avoiding code repetition is "X macros", where you only need to change the values in a single place (called M_LIST in this example):
#include <stdio.h>
#include <inttypes.h>
#define M_LIST(X) \
X(x,0) \
X(y,1) \
X(z,2) \
#define M_enum(symbol,val) M##symbol##_bit = val,
enum { M_LIST(M_enum) };
#define M(symbol) ( 1ull << (M##symbol##_bit) )
int main (void)
{
printf("%.16"PRIx64"\n", M(x));
printf("%.16"PRIx64"\n", M(y));
printf("%.16"PRIx64"\n", M(z));
}
Here a temporary enum is created, which will expand to:
enum { Mx_bit = 0, My_bit = 1, Mz_bit = 2, }. These constants aren't used directly by your program, but only through the macro M.

Error in C preprocessor concatenation with variable and function (dynamically indexing in a for loop)

I ran this code in this compiler
#define CCc(n) CC_##n
#define CC(n) CCc(n)
#define CC_1 (1,2)
#define CC_2 (3,4)
#define CALL_FUNCTION(xy) Coord(xy)
#define YES 1
#define NO 0
int Coord(x, y){
if (x < 0.5 && y < 1.5){
return YES;
}
return NO;
}
int main()
{
for(int i = 1; i < 3; i++){
CALL_FUNCTION(CC(i));
}
return 0;
}
and got this error:
error: use of undeclared identifier 'CC_i'
Why does this error occur? And what is the right way to achieve this?
You cannot do run-time/variable evaluations in the pre-processor. It requires compile-time pre-processor tokens. So rather than trying to define a number of #define based on run-time values, you should gather all compile-time constants in one place.
A common way to do so is "X macros". In your case it might look like this:
#define CC_LIST \
/* n x y */ \
X(1, 1, 2) \
X(2, 3, 4) \
int main()
{
#define X(n,x,y) (void) Coord(x, y);
CC_LIST
#undef X
return 0;
}
This expands to (void) Coord(1,2); (void) Coord(3,4);, so it is a compile-time loop unrolling of sorts.
Alternatively, if you insist on having the "CC_N" macros because they are also needed for other purposes, you can do this:
#define CC_LIST \
/* n */ \
X(1) \
X(2) \
#define CC(n) CC_##n
#define CC_1 1,2
#define CC_2 3,4
#define CALL_FUNCTION(...) (void) Coord(__VA_ARGS__);
int main()
{
#define X(n) CALL_FUNCTION(CC(n))
CC_LIST
#undef X
return 0;
}
As you can tell, macro tricks like "X macros" are not easy to read and should be regarded as the last resort. Only use them when proper program re-design is not possible, for example during maintenance of existing code.

How to write generic #define macro in C and write less code

Let's say I have 2 sets of values for P_A, P_B, P_C as below
#define X_P_A 2
#define X_P_B 3
#define X_P_C 4
#define Y_P_A 5
#define Y_P_B 6
#define Y_P_C 7
There are 3 types of users:- once that only need X variants, once that only need Y variants and once those may need both.
eg
#ifdef X
#define P_A X_P_A
#define P_B X_P_B
#define P_C X_P_C
#endif
#ifdef Y
#define P_A Y_P_A
#define P_B Y_P_B
#define P_C Y_P_C
#endif
Users that need both will make the decision at run time and call X_P_<> or Y_P_<> as needed.
Is there a way to make it simpler, so that I don't have to write conditional macros for each field
ifdef X
// do something magical does defines all P_<> to X_P_<>
#endif
I know it sounds stupid. You may ask why not just use X_P_<> variants on X. I am just trying to understand if it is possible.
I am okay with changing the way the macros the defined.
Is something similar to below code possible : (problem with below code is that compilation fails because #if not allowed within #define)
#define A 1
#define B 2
#define C 3
/* Not a correct #define macro */
#define X_P(x) \
#if(x == A) 2 \
#elif(x == B) 3 \
#elif(x == C) 4 \
#endif
#ifdef X
#define P(x) X_P(x)
#endif
You could do it with one variant of X-Macros:
#define IMPLEMENT(X) \
X(P_A, 1, 5) \
X(P_B, 2, 6) \
X(P_C, 3, 7)
enum {
// Just one
#define X1_P(n, x, y) n = x,
IMPLEMENT(X1_P)
// Both
#define X2_P(n, x, y) X_##n = x,
#define Y2_P(n, x, y) Y_##n = y,
IMPLEMENT(X2_P)
IMPLEMENT(Y2_P)
DUMMY // Just in case compiler is strict about trailing comma
};
Which would expand to:
enum {
P_A = 1, P_B = 2, P_C = 3,
X_P_A = 1, X_P_B = 2, X_P_C = 3,
Y_P_A = 5, Y_P_B = 6, Y_P_C = 7,
DUMMY
};
#define X_P(x) ((x) - 0x10 + 1) // 1 is 0x31 and A is 0x41 hence A will give 0x41 - 0x10 + 1 = 0x32
#define Y_P(y) ((y) - 0x10 + 5) // same logic applies
Would it be what you are looking for ? Not fully answering your question though

C macro for calculate the max number of a bunch of definitions

I need to find the Max value with a macro beetween 55 values defined also as macro definitions. I mean
#define VALUE1 56
#define VALUE2 76
...
#define VALUE55 14
#define MAX_BEETWEEN_VALUES (...) ...
the macro function MAX_BEETWEEN_VALUES should return 76 as result.
I canĀ“t figure out how this macro should be coded.
Thanks for your help
Here's another C kludge to find the maximum at compile-time. Assuming that enumerations work as well as #defines for you and that the values are small positive integers (though there are even worse workarounds for other domains).
union value_set_t {
# define V(name, value) char name##_[value];
# include "values.h"
# undef V
};
enum {
# define V(name, value) name = value,
# include "values.h"
# undef V
MAX_BETWEEN_VALUES = sizeof(union value_set_t)
};
With values.h:
V(VALUE1, 56)
V(VALUE2, 76)
V(VALUE55, 14)
Code for my comment to answer above: https://stackoverflow.com/a/20221017/2963099
V1 to V58 not shown
#define V59 1
#define V60 33
#define V61 1
#define V62 2
#define V63 1
#define V64 2
#define MAX2(a,b) ((a>b)?(a):(b))
#define MAX4(a,b,c,d) MAX2(MAX2(a,b), MAX2(c,d))
#define MAX8(a,b,c,d,e,f,g,h) MAX2(MAX4(a,b,c,d),MAX4(e,f,g,h))
#define MAX64(a1,a2,a3,a4,a5,a6,a7,a8, \
b1,b2,b3,b4,b5,b6,b7,b8, \
c1,c2,c3,c4,c5,c6,c7,c8, \
d1,d2,d3,d4,d5,d6,d7,d8, \
e1,e2,e3,e4,e5,e6,e7,e8, \
f1,f2,f3,f4,f5,f6,f7,f8, \
g1,g2,g3,g4,g5,g6,g7,g8, \
h1,h2,h3,h4,h5,h6,h7,h8) MAX8(\
MAX8(a1,a2,a3,a4,a5,a6,a7,a8), \
MAX8(b1,b2,b3,b4,b5,b6,b7,b8), \
MAX8(c1,c2,c3,c4,c5,c6,c7,c8), \
MAX8(d1,d2,d3,d4,d5,d6,d7,d8), \
MAX8(e1,e2,e3,e4,e5,e6,e7,e8), \
MAX8(f1,f2,f3,f4,f5,f6,f7,f8), \
MAX8(g1,g2,g3,g4,g5,g6,g7,g8), \
MAX8(h1,h2,h3,h4,h5,h6,h7,h8))
int main(int, char**)
{
int x= MAX64(V1,V2,V3,V4,V5,V6,V7,V8,V9,V10,V11,V12,V13,V14,V15,V16,V17,V18,V19,V20,V21,V22,V23,V24,V25,V26,V27,V28,V29,V30,V31,V32,V33,V34,V35,V36,V37,V38,V39,V40,V41,V42,V43,V44,V45,V46,V47,V48,V49,V50,V51,V52,V53,V54,V55,V56,V57,V58,V59,V60,V61,V62,V63,V64);
return x;
}
Compiles pretty quickly (and has 33 as correct answer)
Hard code
#define MAX(X, Y) ((X>Y)?(X):(Y))
#define MAX_BEETWEEN_VALUES MAX(VALUE1, \
MAX(VALUE2, \
MAX(VALUE3, \
... \
MAX(VALUE54, \
VALUE55))) ... )
~~~~~~~~~ 54 close parenthesis
It may exceed compiler's limitations.
A novel (and fairly evil) approach to generating having many/max macros could be to generate them.
Example Python script:
def minmax(a, expr):
t = "("
t = t + ("(%s%s%s)?" % (a[0], expr, a[1]))
if len(a) == 2:
r_a = a[0]
r_b = a[1]
else:
r_a = minmax((a[0],) + a[2:], expr)
r_b = minmax(a[1:], expr)
t = t + ("%s:%s" % (r_a, r_b))
return t + ")"
for i in range(2, 8):
args = tuple([("v%d" % j) for j in range(i)])
print((" #define MIN%d(%s) " % (i, ",".join(args)) + minmax(args, "<")))
print((" #define MAX%d(%s) " % (i, ",".join(args)) + minmax(args, ">")))
generates this...
#define MIN2(v0,v1) ((v0<v1)?v0:v1)
#define MAX2(v0,v1) ((v0>v1)?v0:v1)
#define MIN3(v0,v1,v2) ((v0<v1)?((v0<v2)?v0:v2):((v1<v2)?v1:v2))
#define MAX3(v0,v1,v2) ((v0>v1)?((v0>v2)?v0:v2):((v1>v2)?v1:v2))
#define MIN4(v0,v1,v2,v3) ((v0<v1)?((v0<v2)?((v0<v3)?v0:v3):((v2<v3)?v2:v3)):((v1<v2)?((v1<v3)?v1:v3):((v2<v3)?v2:v3)))
#define MAX4(v0,v1,v2,v3) ((v0>v1)?((v0>v2)?((v0>v3)?v0:v3):((v2>v3)?v2:v3)):((v1>v2)?((v1>v3)?v1:v3):((v2>v3)?v2:v3)))
#define MIN5(v0,v1,v2,v3,v4) ((v0<v1)?((v0<v2)?((v0<v3)?((v0<v4)?v0:v4):((v3<v4)?v3:v4)):((v2<v3)?((v2<v4)?v2:v4):((v3<v4)?v3:v4))):((v1<v2)?((v1<v3)?((v1<v4)?v1:v4):((v3<v4)?v3:v4)):((v2<v3)?((v2<v4)?v2:v4):((v3<v4)?v3:v4))))
#define MAX5(v0,v1,v2,v3,v4) ((v0>v1)?((v0>v2)?((v0>v3)?((v0>v4)?v0:v4):((v3>v4)?v3:v4)):((v2>v3)?((v2>v4)?v2:v4):((v3>v4)?v3:v4))):((v1>v2)?((v1>v3)?((v1>v4)?v1:v4):((v3>v4)?v3:v4)):((v2>v3)?((v2>v4)?v2:v4):((v3>v4)?v3:v4))))
#define MIN6(v0,v1,v2,v3,v4,v5) ((v0<v1)?((v0<v2)?((v0<v3)?((v0<v4)?((v0<v5)?v0:v5):((v4<v5)?v4:v5)):((v3<v4)?((v3<v5)?v3:v5):((v4<v5)?v4:v5))):((v2<v3)?((v2<v4)?((v2<v5)?v2:v5):((v4<v5)?v4:v5)):((v3<v4)?((v3<v5)?v3:v5):((v4<v5)?v4:v5)))):((v1<v2)?((v1<v3)?((v1<v4)?((v1<v5)?v1:v5):((v4<v5)?v4:v5)):((v3<v4)?((v3<v5)?v3:v5):((v4<v5)?v4:v5))):((v2<v3)?((v2<v4)?((v2<v5)?v2:v5):((v4<v5)?v4:v5)):((v3<v4)?((v3<v5)?v3:v5):((v4<v5)?v4:v5)))))
#define MAX6(v0,v1,v2,v3,v4,v5) ((v0>v1)?((v0>v2)?((v0>v3)?((v0>v4)?((v0>v5)?v0:v5):((v4>v5)?v4:v5)):((v3>v4)?((v3>v5)?v3:v5):((v4>v5)?v4:v5))):((v2>v3)?((v2>v4)?((v2>v5)?v2:v5):((v4>v5)?v4:v5)):((v3>v4)?((v3>v5)?v3:v5):((v4>v5)?v4:v5)))):((v1>v2)?((v1>v3)?((v1>v4)?((v1>v5)?v1:v5):((v4>v5)?v4:v5)):((v3>v4)?((v3>v5)?v3:v5):((v4>v5)?v4:v5))):((v2>v3)?((v2>v4)?((v2>v5)?v2:v5):((v4>v5)?v4:v5)):((v3>v4)?((v3>v5)?v3:v5):((v4>v5)?v4:v5)))))
#define MIN7(v0,v1,v2,v3,v4,v5,v6) ((v0<v1)?((v0<v2)?((v0<v3)?((v0<v4)?((v0<v5)?((v0<v6)?v0:v6):((v5<v6)?v5:v6)):((v4<v5)?((v4<v6)?v4:v6):((v5<v6)?v5:v6))):((v3<v4)?((v3<v5)?((v3<v6)?v3:v6):((v5<v6)?v5:v6)):((v4<v5)?((v4<v6)?v4:v6):((v5<v6)?v5:v6)))):((v2<v3)?((v2<v4)?((v2<v5)?((v2<v6)?v2:v6):((v5<v6)?v5:v6)):((v4<v5)?((v4<v6)?v4:v6):((v5<v6)?v5:v6))):((v3<v4)?((v3<v5)?((v3<v6)?v3:v6):((v5<v6)?v5:v6)):((v4<v5)?((v4<v6)?v4:v6):((v5<v6)?v5:v6))))):((v1<v2)?((v1<v3)?((v1<v4)?((v1<v5)?((v1<v6)?v1:v6):((v5<v6)?v5:v6)):((v4<v5)?((v4<v6)?v4:v6):((v5<v6)?v5:v6))):((v3<v4)?((v3<v5)?((v3<v6)?v3:v6):((v5<v6)?v5:v6)):((v4<v5)?((v4<v6)?v4:v6):((v5<v6)?v5:v6)))):((v2<v3)?((v2<v4)?((v2<v5)?((v2<v6)?v2:v6):((v5<v6)?v5:v6)):((v4<v5)?((v4<v6)?v4:v6):((v5<v6)?v5:v6))):((v3<v4)?((v3<v5)?((v3<v6)?v3:v6):((v5<v6)?v5:v6)):((v4<v5)?((v4<v6)?v4:v6):((v5<v6)?v5:v6))))))
#define MAX7(v0,v1,v2,v3,v4,v5,v6) ((v0>v1)?((v0>v2)?((v0>v3)?((v0>v4)?((v0>v5)?((v0>v6)?v0:v6):((v5>v6)?v5:v6)):((v4>v5)?((v4>v6)?v4:v6):((v5>v6)?v5:v6))):((v3>v4)?((v3>v5)?((v3>v6)?v3:v6):((v5>v6)?v5:v6)):((v4>v5)?((v4>v6)?v4:v6):((v5>v6)?v5:v6)))):((v2>v3)?((v2>v4)?((v2>v5)?((v2>v6)?v2:v6):((v5>v6)?v5:v6)):((v4>v5)?((v4>v6)?v4:v6):((v5>v6)?v5:v6))):((v3>v4)?((v3>v5)?((v3>v6)?v3:v6):((v5>v6)?v5:v6)):((v4>v5)?((v4>v6)?v4:v6):((v5>v6)?v5:v6))))):((v1>v2)?((v1>v3)?((v1>v4)?((v1>v5)?((v1>v6)?v1:v6):((v5>v6)?v5:v6)):((v4>v5)?((v4>v6)?v4:v6):((v5>v6)?v5:v6))):((v3>v4)?((v3>v5)?((v3>v6)?v3:v6):((v5>v6)?v5:v6)):((v4>v5)?((v4>v6)?v4:v6):((v5>v6)?v5:v6)))):((v2>v3)?((v2>v4)?((v2>v5)?((v2>v6)?v2:v6):((v5>v6)?v5:v6)):((v4>v5)?((v4>v6)?v4:v6):((v5>v6)?v5:v6))):((v3>v4)?((v3>v5)?((v3>v6)?v3:v6):((v5>v6)?v5:v6)):((v4>v5)?((v4>v6)?v4:v6):((v5>v6)?v5:v6))))))
The macro doubles in length with each argument added, so I wouldn't recommend this for large arrays. however if all values are literals the compiler will likely resolve the result for you.
There might be a standardized way, but if not it's easy enough to just do it, if you're willing to go the "a better C" route.
#include <cstdio>
template<int a, int ...list> struct greatest_of {
static const int value = a > greatest_of<list...>::value
? a : greatest_of<list...>::value;
};
template<int a> struct greatest_of<a> {
static const int value = a;
};
int main()
{
printf("%d\n",greatest_of<1,2,3>::value);
}
(edit: printf).

Resources