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

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

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.

save expanded macro result before it is undefined

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...

C Preprocessor generate macros by concatenation and stringification [duplicate]

This question already has answers here:
What are the applications of the ## preprocessor operator and gotchas to consider?
(13 answers)
Closed 7 years ago.
I have a set of target macros for which I want to generate aliases based on a choosing macro, like so:
Choosing macro:
#define I2C_MODULE 1
Alias macros (conceptual form):
#define I2C_MODULE_BASE I2C<Value of I2C_MODULE>_BASE
#define I2C_MODULE_NVIC INT_I2C<Value of I2C_MODULE>
Target macros (from an external file out of my control):
#define INT_I2C0 24
#define INT_I2C1 53
...
#define I2C0_BASE 0x40020000
#define I2C1_BASE 0x40021000
...
I wanted to have the preprocessor generate the alias macros I2C_MODULE_BASE and I2C_MODULE_NVIC based on the
choosing macro I2C_MODULE, but after much reading Q1, P1 and many other references I lost track of, I ended up hard-coding their values. Below I show my current working definitions, and then my last failed attempts at generating the macros:
What works:
#define I2C_MODULE 1
#define I2C_MODULE_BASE I2C1_BASE
#define I2C_MODULE_NVIC INT_I2C1
what did not work:
#define I2C_MODULE 1
#define STR_HELPER(x) #x
#define STR(x) STR_HELPER(x)
/* Attempt 1 */
#define I2C_MODULE_BASE "I2C" STR(I2C_MODULE) "_BASE"
#define I2C_MODULE_NVIC "INT_I2C" STR(I2C_MODULE)
/* Attempt 2 */
#define _I2C_MODULE_BASE "I2C" STR(I2C_MODULE) "_BASE"
#define _I2C_MODULE_NVIC "INT_I2C" STR(I2C_MODULE)
#define I2C_MODULE_BASE _I2C_MODULE_BASE
#define I2C_MODULE_NVIC _I2C_MODULE_NVIC
EDIT: I expanded upon the accepted answer to get to where I wanted, as follows:
#define PASTE2(a, b) a ## b
#define PASTE3(a, b, c) a ## b ## c
#define _I2C_MODULE_BASE(x) PASTE3(I2C, x, _BASE)
#define _I2C_MODULE_NVIC(x) PASTE2(INT_I2C, x)
#define I2C_MODULE_BASE _I2C_MODULE_BASE(I2C_MODULE)
#define I2C_MODULE_NVIC _I2C_MODULE_NVIC(I2C_MODULE)
This seems to work:
#define I2C_MODULE 1
//Alias macros (conceptual form):
//#define I2C_MODULE_BASE I2C<Value of I2C_MODULE>_BASE
//#define I2C_MODULE_NVIC INT_I2C<Value of I2C_MODULE>
//Target macros (from an external file out of my control):
#define INT_I2C0 24
#define INT_I2C1 53
#define I2C0_BASE 0x40020000
#define I2C1_BASE 0x40021000
#define PASTE2(a, b) a ## b
#define PASTE3(a, b, c) a ## b ## c
#define I2C_MODULE_BASE(x) PASTE3(I2C, x, _BASE)
#define I2C_MODULE_NVIC(x) PASTE2(INT_I2C, x)
extern int i2c_module_base = I2C_MODULE_BASE(I2C_MODULE);
extern int i2c_module_nvic = I2C_MODULE_NVIC(I2C_MODULE);
extern int i2c_module_base_0 = I2C_MODULE_BASE(0);
extern int i2c_module_nvic_0 = I2C_MODULE_NVIC(0);
extern int i2c_module_base_1 = I2C_MODULE_BASE(1);
extern int i2c_module_nvic_1 = I2C_MODULE_NVIC(1);
Sample output (from cpp):
# 1 "xx.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "xx.c"
# 21 "xx.c"
extern int i2c_module_base = 0x40021000;
extern int i2c_module_nvic = 53;
extern int i2c_module_base_0 = 0x40020000;
extern int i2c_module_nvic_0 = 24;
extern int i2c_module_base_1 = 0x40021000;
extern int i2c_module_nvic_1 = 53;
It is closely based on my answer to C preprocessor and token concatenation.
There are undoubtedly other ways that the I2C_MODULE_BASE and I2C_MODULE_NVIC macros could be written, but the key points are:
Using the ## token pasting operator (not the # stringifying operator).
Using two levels of macro (for example, I2C_MODULE_BASE and PASTE3).
I suspect that you are writing a I2C driver which can generically handle multiple I2C hardware peripherals in the same micro-controller without rewriting all the same code multiple times.
In that case, what you are really looking for probably is something like this:
#define I2C1 ((volatile uint8_t*)0x12345678) // address of first hw register for I2C1
#define I2C2 ((volatile uint8_t*)0x55555555) // address of first hw register for I2C2
/* map all registers used for I2C, they will have same register layout for every
peripheral no matter which one: */
#define I2C_CONTROL(base) (*(base + 0))
#define I2C_DATA(base) (*(base + 1))
...
// create some dummy typedef to make your functions look nice:
typedef volatile uint8_t* I2C_t;
// define whatever functions you need in the driver:
void i2c_init (IC2_t bus);
void i2c_send (I2C_t bus, const uint8_t* data, size_t n);
...
// implement functions in a bus-independent way:
void i2c_init (IC2_t bus)
{
I2C_CONTROL(bus) = THIS | THAT; // setup registers
}
// caller code:
i2c_init(I2C1);
i2c_init(I2C2);
...
i2c_send(I2C1, "hello", 5);
i2c_send(I2C2, "world", 5);
Just use #if / #else / #endif
#if (I2C_MODULE == 0)
#define I2C_MODULE_BASE I2C0_BASE
#define I2C_MODULE_NVIC INT_I2C0
#elif (I2C_MODULE == 1)
#define I2C_MODULE_BASE I2C1_BASE
#define I2C_MODULE_NVIC INT_I2C1
#else
#error Unknown configuration
#endif

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