Compile time error with Macro definitions - Preprocessor token expansions - c

Any help with the below would be greatly appreciated as I'm highly blocked at this point for almost a day not knowing how to proceed :(
The below code is from a WiFi 3rd party vendor and I'm supposed to only integrate the source code as it is.
(GCC version is 7)
Errors I get to see during compilation of the source code in c is:
cmn_dev/spectral/../../cmn_dev/cfg/inc/i_cfg.h:68:1: error: macro "__CFG" requires 4 arguments, but only 2 given
CFG_ALL
^~~~~~~~
/cmn_dev/spectral/../../cmn_dev/cfg/inc/cfg_define.h:41:24: error: expected specifier-qualifier-list before '__CFG'
#define _CFG(id, args) __CFG(id, args)
Snippet at cfg_define.h
#define rm_parens(...) __VA_ARGS__
#define __CFG(id, is_ini, mtype, args...) __CFG_##is_ini##_##mtype(id, mtype, args)
#define _CFG(id, args) __CFG(id, args)
#define CFG(id) _CFG(__##id, rm_parens id)
Snippet at i_cfg.h
struct cfg_values {
/* e.g. const int32_t __CFG_SCAN_DWELL_TIME_internal; */
CFG_ALL
};
Snippet at cfg_all.h
#define CFG_ALL \
CFG_OL \
CFG_SA \
CFG_NSS \
CFG_CONVERGED_ALL \
CFG_TARGET
Please let me know if any other info is required.
Thanks in advance!
PS:
**Major Error is:
/cmn_dev/spectral/../../cmn_dev/cfg/inc/i_cfg.h:63:1: error: macro "__CFG" requires 4 arguments, but only 2 given
CFG_ALL **
struct cfg_values {
/* e.g. const int32_t __CFG_SCAN_DWELL_TIME_internal; */
CFG_ALL
};```
```#define CFG_ALL \
CFG_OL \
CFG_SA \
CFG_NSS \
CFG_CONVERGED_ALL \
CFG_TARGET ```
<...>
```define CFG_OL \
CFG(CFG_OL_ENABLE_11AX_STUB) \
CFG(CFG_OL_TX_TCP_CKSUM) \
CFG(CFG_OL_VOW_CONFIG) \
CFG(CFG_OL_CARRIER_VOW_CONFIG) \
CFG(CFG_OL_FW_VOW_STATS_ENABLE) \
CFG(CFG_OL_QWRAP_ENABLE) \
CFG(CFG_OL_CCE_DISABLE) \
<....so on> ```
```#define rm_parens(...) __VA_ARGS__
#define __CFG(id, is_ini, mtype, args...) \
__CFG_##is_ini##_##mtype(id, mtype, args)
#define _CFG(id, args) __CFG(id, args)
//#define CFG(id) _CFG(__##id, rm_parens id)
#define CFG(id) _CFG(__##id, rm_parens (id)) //MODIFIED_REF ```
Further defs,
```#define CFG_OL_ENABLE_11AX_STUB \
CFG_INI_BOOL("enable_11ax_stub", false, \
"Enable 802.11ax stubbing support for testing. Valid only for QCA9984")
#define CFG_OL_TX_TCP_CKSUM \
CFG_INI_BOOL("enable_tx_tcp_cksum", false, \
"Enable Tx TCP Checksum")
#define CFG_OL_VOW_CONFIG \
CFG_INI_BOOL("vow_config", false, \
"VoW Configuration")
<... and so on>
#define CFG_INI_INT(name, min, max, def, fallback, desc) \
(INI, INT, int32_t, name, min, max, fallback, desc, def)
#define CFG_INI_UINT(name, min, max, def, fallback, desc) \
(INI, UINT, uint32_t, name, min, max, fallback, desc, def)
#define CFG_INI_BOOL(name, def, desc) \
(INI, BOOL, bool, name, false, true, -1, desc, def)
#define CFG_INI_STRING(name, min_len, max_len, def, desc) \
(INI, STRING, char *, name, min_len, max_len, -1, desc, def)
#define CFG_INI_MAC(name, def, desc) \
(INI, MAC, struct qdf_mac_addr, name, -1, -1, -1, desc, def)
#define CFG_INI_IPV4(name, def, desc) \
(INI, IPV4, struct qdf_ipv4_addr, name, -1, -1, -1, desc, def)
#define CFG_INI_IPV6(name, def, desc) \
(INI, IPV6, struct qdf_ipv6_addr, name, -1, -1, -1, desc, def)```

Related

How does the C preprocessor go from a macro to a struct definition

As I was searching for a way to do reflection in C, I found this answer https://stackoverflow.com/a/31908340/6784916.
In his answer, he refers to the metaresc library and he shows an example how to use it:
TYPEDEF_STRUCT (point_t,
double x,
double y
);
int main (int argc, char * argv[])
{
point_t point = {
.x = M_PI,
.y = M_E,
};
...
}
TYPEDEF_STRUCT is defined on line 237 of https://github.com/alexanderchuranov/Metaresc/blob/master/src/metaresc.h
I tried extracting the source of the macro but I'm not sure if I missed something because it's so complex.
#define TYPEDEF_STRUCT(...) P00_TYPEDEF (STRUCT, __VA_ARGS__)
#ifndef MR_MODE
#define MR_MODE_UNDEFINED
#define MR_MODE PROTO
#endif
#include <mr_protos.h>
#ifdef MR_MODE_UNDEFINED
#undef MR_MODE_UNDEFINED
#undef MR_MODE
#endif
#define MR_IS_MR_MODE_EQ_MR_MODE 0
#define P00_TYPEDEF(...) \
MR_IF_ELSE (MR_PASTE2 (MR_IS_MR_MODE_EQ_, MR_MODE)) \
(P00_TYPEDEF_MODE (MR_MODE, __VA_ARGS__)) \
(P00_TYPEDEF_MODE (PROTO, __VA_ARGS__) P00_TYPEDEF_MODE (DESC, __VA_ARGS__))
#define MR_IGNORE(...)
#define MR_IDENT(...) __VA_ARGS__
#define MR_IF_ELSE_CASE_0(...) __VA_ARGS__ MR_IGNORE
#define MR_IF_ELSE_CASE_1(...) MR_IDENT
#define MR_IF_ELSE(...) MR_PASTE2 (MR_IF_ELSE_CASE_, MR_IS_EQ_0 (__VA_ARGS__))
#define MR_PASTE2(...) MR_PASTE2_ (__VA_ARGS__)
#define MR_PASTE2_(_0, _1) _0 ## _1
#define MR_IS_0_EQ_0 ,
#define MR_IS_EQ_0_CASE_011 ,
#define MR_GET_SECOND(_0, ...) __VA_ARGS__
#define MR_IS_EQ_0(...) MR_IS_EQ_0_ (__VA_ARGS__) /* evaluate arguments */
#define MR_IS_EQ_0_(...) MR_IS_EQ_0__ ((__VA_ARGS__), (MR_PASTE2 (MR_IS_0_EQ_, __VA_ARGS__)))
#define MR_IS_EQ_0__(ARGS, ARGS_EQ_0) \
MR_HAS_COMMA (MR_PASTE4 (MR_IS_EQ_0_CASE_, \
/* test if there is just one argument, eventually a zero */ \
MR_HAS_COMMA ARGS, \
/* test if MR_IS_0_EQ_ together with the argument adds a comma */ \
MR_HAS_COMMA ARGS_EQ_0, \
/* test that there is nothing after comma */ \
MR_IS_EMPTY (MR_GET_SECOND ARGS_EQ_0)))
#define P00_TYPEDEF_MODE(P00_MODE, P00_TYPE, ...) \
P00_TYPEDEF_MODE_ (P00_MODE, P00_TYPE, \
ATTRIBUTES (P00_GET_ATTRIBUTES (__VA_ARGS__)), \
P00_GET_NON_ATTRIBUTES (__VA_ARGS__))
#define P00_TYPEDEF_MODE_(...) P00_TYPEDEF_MODE__ (__VA_ARGS__)
#define P00_TYPEDEF_MODE__(P00_MODE, P00_TYPE, ATTR_META_RES, ...) \
#define P00_GET_ATTRIBUTES(...) MR_FOREACH (P00_EXTRACT_ATTRIBUTES, __VA_ARGS__)
#define P00_GET_NON_ATTRIBUTES(...) MR_FOREACH (P00_EXTRACT_NON_ATTRIBUTES, __VA_ARGS__)
#define MR_FOREACH(X, ...) MR_PASTE2 (MR_FOREACH, MR_NARG (__VA_ARGS__)) (X, __VA_ARGS__)
#define MR_FOR(NAME, N, OP, FUNC, ...) MR_PASTE2 (MR_FOR, N) (NAME, OP, FUNC, __VA_ARGS__)
#define P00_TYPEDEF_ATTR_STRUCT TYPEDEF_ATTR
#define P00_TYPEDEF_ATTR_UNION TYPEDEF_ATTR
#define P00_TYPEDEF_ATTR_ENUM TYPEDEF_ATTR
#define P00_TYPEDEF_ATTR_CHAR_ARRAY(P00_MODE, P00_TYPE, ATTR_META_RES, P00_TYPE_NAME, SIZE, ...) MR_PASTE2 (MR_TYPEDEF_CHAR_ARRAY_, P00_MODE) (P00_TYPE_NAME, SIZE, MR_PASTE2 (P00_REMOVE_, ATTR_META_RES), __VA_ARGS__)
#define P00_TYPEDEF_ATTR_FUNC(P00_MODE, P00_TYPE, ATTR_META_RES, RET_TYPE, P00_TYPE_NAME, ARGS, ...) MR_PASTE2 (MR_TYPEDEF_FUNC_, P00_MODE) (RET_TYPE, P00_TYPE_NAME, ARGS, MR_PASTE2 (P00_REMOVE_, ATTR_META_RES), __VA_ARGS__)
#define P00_UNFOLD(PREFIX, P00_TYPE, P00_MODE, ...) MR_PASTE4 (PREFIX, P00_TYPE, _, P00_MODE) (__VA_ARGS__)
#define TYPEDEF_ATTR(P00_MODE, P00_TYPE, ATTR_META_RES, P00_TYPE_NAME, ...) \
P00_UNFOLD (MR_TYPEDEF_, P00_TYPE, P00_MODE, P00_TYPE_NAME, MR_PASTE2 (P00_GET_FIRST_, ATTR_META_RES)) \
MR_FOR ((P00_MODE, P00_TYPE_NAME), MR_NARG (__VA_ARGS__), MR_SER, MR_PASTE3 (P00_, P00_TYPE, _HANDLER), __VA_ARGS__) \
P00_UNFOLD (MR_END_, P00_TYPE, P00_MODE, P00_TYPE_NAME, MR_PASTE2 (P00_GET_OTHER_, ATTR_META_RES))
# define P00_IS_ATTRIBUTES_EQ_ATTRIBUTES(...) 0 /* help macro for ATTRIBUTES test IF clause */
#define P00_REMOVE_ATTRIBUTES(...) __VA_ARGS__
#define P00_GET_FIRST_ATTRIBUTES(FIRST, ...) FIRST /* extract typedef attributes */
#define P00_GET_OTHER_ATTRIBUTES(FIRST, ...) __VA_ARGS__ /* extract typedef meta information */
All I want to know is how can a macro call such as
TYPEDEF_STRUCT (point_t,
double x,
double y
);
expand to that
typedef struct point_t {
double x;
double y;
} point_t;
I'm not sure why do you want to decouple headers from the rest of the library. Probably first 700 lines of metaresc.h are used in TYPEDEF_STRUCT, so you will need most of this file. Even though it will not help you, just because result of the macro is typedef + meta-data required for serialization. Serialization functions are implemented in the library, so there is no sense to decouple meta-data generation from the code that uses this meta-data.
You could run example through preprocessor and evaluate outcome. This will give you and idea what do I mean as meta-data.
If you are really interested in understanding of TYPEDEF_STRUCT macro implementation details, then get ready for 100+ layers of nested macros. As a first exercises you could start here https://gustedt.wordpress.com/2010/06/08/detect-empty-macro-arguments/ and continue with other macro tricks from https://p99.gforge.inria.fr/

Parametrized generic C macros

I'm playing around with building a psuedo-generic type in C. Essentially, I'm trying to clone Rust's Option<T> with a predefined, constrained list of types allowable as T.
Obviously, C isn't really suited for this -- I'm doing this primarily to see how far I can go (as opposed to something I'd expect to use in real production code). To that end, any ugly hacks are fair game.
What I have so far builds out a separate set of inner-type-specific functions for all provided types. It looks something like this:
Header:
#pragma once
#define ALL_OPTIONS \
OPTION_INSTANCE(option_bool, bool) \
OPTION_INSTANCE(option_double, double) \
OPTION_INSTANCE(option_int, int)
#define OPTION_INSTANCE(name, inner) \
typedef struct { \
bool is_some; \
inner val; \
} name##_t;
ALL_OPTIONS
#undef OPTION_INSTANCE
#define OPTION_INSTANCE(name, inner) \
name##_t name##_some(inner val); \
name##_t name##_none(void); \
bool name##_is_some(name##_t self); \
bool name##_is_none(name##_t self); \
ALL_OPTIONS
#undef OPTION_INSTANCE
Implementation:
#include "option.h"
#define OPTION_INSTANCE(name, inner) \
name##_t name##_some(inner val) { \
return (name##_t) { \
.is_some = true, \
.val = val, \
}; \
} \
\
name##_t name##_none(void) { \
return (name##_t) { \
.is_some = false, \
}; \
} \
\
bool name##_is_some(name##_t self) { \
return self.is_some; \
} \
\
bool name##_is_none(name##_t self) { \
return !self.is_some; \
}
ALL_OPTIONS
#undef OPTION_INSTANCE
Note that in my actual code I have many more functions defined for the generated types.
This works well enough, though primarily all I've done is reduce implementation boilerplate. The next step would be to implement option_is_some (no type qualification) which can accept any option_<inner>_t
I can do that well enough with a manual macro, leveraging C11 generics:
#define option_is_some(self) \
_Generic((self), \
option_bool_t: option_bool_is_some, \
option_double_t: option_double_is_some, \
option_int_t: option_int_is_some, \
)(self)
but this necessarily duplicates the list of types defined in ALL_OPTIONS. What I'd really like to do would be something like
#define OPTION_INSTANCE(name, inner) \
name##_t: name##_is_some,
#define option_is_some(self) \
_Generic((self), \
ALL_OPTIONS \
default: false \
)(self)
#undef OPTION_INSTANCE
but that fails, since ALL_OPTIONS is expanded when option_is_some is used (where OPTION_INSTANCE will be undefined).
So, I'm looking for alternatives. I'd happily move to a radically different method of defining a generic list of types (instead of the ALL_OPTIONS hack) -- however, I do want to preserve the property that adding a new supported inner type only requires a change in a single location.
Just access the member in the macro itself:
#define option_is_some(self) ((self).is_some)
Overall, your implementation is strange. Do not have a central ALL_OPTIONS place - do one option at a time, separately from each other. Files are split into headers and source files in C.
#define OPTION_HEADER(name, inner) \
typedef struct { \
bool is_some; \
inner val; \
} name##_t; \
\
name##_t name##_some(inner val); \
name##_t name##_none(void); \
bool name##_is_some(name##_t self); \
bool name##_is_none(name##_t self);
#define OPTION_SOURCE(name, inner) \
name##_t name##_some(inner val) { \
return (name##_t) { \
.is_some = true, \
.val = val, \
}; \
} \
etc...
#define OPTION_HEADER_AND_SOURCE(name, ...) \
OPTION_HEADER(name, __VA_ARGS__)
OPTION_SOURCE(name, __VA_ARGS__)
Then you would just do the options:
OPTION_HEADER_AND_SOURCE(option_bool, bool)
OPTION_HEADER_AND_SOURCE(option_double, double)
OPTION_HEADER_AND_SOURCE(option_int, int)
You can take a look at other projects that I've found: https://github.com/tylov/STC and https://github.com/glouw/ctl that use macro-ish templates to implement in C various container known from C++.

C99 compatible nested calls within variadic macros

Need a way to support nested calls in variadic macros with optional argument. same as this but C99 compatible
GNU gcc extension for ## operator prevents nested calls from being expanded, see code below.
#define send(obj, msg, ...) find_method(obj, msg)(obj, ##__VA_ARGS__)
/* Ok */
send(0, "+", 1);
find_method(0, "+")(0, 1);
/* Ok. nested call as macros named argument */
send(send(5, "increment"), "+", 1);
find_method(find_method(5, "increment")(5), "+")(find_method(5, "increment")(5), 1);
/* Fail. nested call as macros variable argument i.e. `send` macro is not expanded */
send(0, "+", send(5, "increment"));
find_method(0, "+")(0, send(5, "increment"));
/*
* preprocess with next commands
*
* gcc-4.9 -Wall -std=c99 -E -c file.c | less
* clang-3.8 -Wall -std=c99 -E -c file.c | less
*/
I've modified Jens Gustedt solution to place optional comma, see code below.
Are there more concise alternatives ?
#define _ARG16( \
_0, _1, _2, _3, _4, \
_5, _6, _7, _8, _9, \
_10, _11, _12, _13, _14, \
_15, ...) _15
#define HAS_COMMA(...) \
_ARG16(__VA_ARGS__, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0)
#define _TRIGGER_PARENTHESIS_(...) ,
#define OPTIONAL_COMMA(...) \
_ISEMPTY( \
/* test if there is just one argument, eventually an empty \
one */ \
HAS_COMMA(__VA_ARGS__), \
/* test if _TRIGGER_PARENTHESIS_ together with the argument \
adds a comma */ \
HAS_COMMA(_TRIGGER_PARENTHESIS_ __VA_ARGS__), \
/* test if the argument together with a parenthesis \
adds a comma */ \
HAS_COMMA(__VA_ARGS__ (/*empty*/)), \
/* test if placing it between _TRIGGER_PARENTHESIS_ and the \
parenthesis adds a comma */ \
HAS_COMMA(_TRIGGER_PARENTHESIS_ __VA_ARGS__ (/*empty*/)) \
)
#define SPACE_SYMBOL
#define COMMA_SYMBOL ,
#define ARG3(_0, _1, _2, ...) _2
#define OPTIONAL_COMMA_FROM(...) ARG3(__VA_ARGS__, SPACE_SYMBOL, COMMA_SYMBOL)
#define PASTE5(_0, _1, _2, _3, _4) _0 ## _1 ## _2 ## _3 ## _4
#define _ISEMPTY(_0, _1, _2, _3) \
OPTIONAL_COMMA_FROM(PASTE5(_IS_EMPTY_CASE_, _0, _1, _2, _3))
#define _IS_EMPTY_CASE_0001 ,
#define send(obj, msg, ...) \
find_method(obj, msg)(obj OPTIONAL_COMMA(__VA_ARGS__) __VA_ARGS__)
/* Ok */
send(0, "+", 1);
/* Ok */
send(send(5, "increment"), "+", 1);
/* Ok */
send(0, "+", send(5, "increment"));
Update:
H Walters thanks for idea.
Didn't noticed approach with macros overloading in first place
#define SEND_NO_ARG(obj, msg) find_method(obj, msg)(obj)
#define SEND_ARG(obj, msg, ...) find_method(obj, msg)(obj, __VA_ARGS__)
#define GET_18TH_ARG(arg1, arg2, arg3, arg4, arg5, \
arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, \
arg14, arg15, arg16, arg17, arg18, ...) arg18
#define SEND_MACRO_SELECTOR(...) \
GET_18TH_ARG(__VA_ARGS__, \
SEND_ARG, SEND_ARG, SEND_ARG, SEND_ARG, SEND_ARG, \
SEND_ARG, SEND_ARG, SEND_ARG, SEND_ARG, SEND_ARG, \
SEND_ARG, SEND_ARG, SEND_ARG, SEND_ARG, SEND_ARG, \
SEND_NO_ARG, )
#define send(...) SEND_MACRO_SELECTOR(__VA_ARGS__)(__VA_ARGS__)
This approach is slightly more concise (10 macros vs 12), and at least to my eyes a bit more organized (more of the macros are general purpose):
#define GLUE(A,B) GLUE_I(A,B)
#define GLUE_I(A,B) A##B
#define FIRSTOFMANY(X,...) X
// This can be used as a pattern matcher on the first argument.
// Generally, the first argument is ignored; but if it's
// an object-like macro whose expansion has a comma, it can
// shift a new second argument in that's returned.
// Thus, you can build a "query pattern" as the first argument,
// pass a "default" as the second, and override the default with
// "matched pattern macros".
#define SECOND(...) SECOND_I(__VA_ARGS__,,)
#define SECOND_I(_,X,...) X
// Expands to a count of arguments (min 1, max 15).
#define COUNT(...) COUNT_I(__VA_ARGS__,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,)
#define COUNT_I(_,_15,_14,_13,_12,_11,_10,_9,_8,_7,_6,_5,_4,_3,_2,X,...) X
#define send(obj, ...) \
find_method(obj, FIRSTOFMANY(__VA_ARGS__,)) \
( \
/* select a macro based on ... count (default SEND_LONG) */ \
SECOND(GLUE(WHEN_SEND_VCNT_EQ_,COUNT(__VA_ARGS__)),SEND_LONG)\
(obj, __VA_ARGS__) \
)
#define SEND_LONG(X,Y,...) X,__VA_ARGS__
// Use FIRSTOFMANY when send's varying arg count is 1
#define WHEN_SEND_VCNT_EQ_1 , FIRSTOFMANY
...it's also C99 compliant (not relying on gnu extensions).
macros overloading technique provides shortest code so far.
#define SEND_NO_ARG(obj, msg) find_method(obj, msg)(obj)
#define SEND_ARG(obj, msg, ...) find_method(obj, msg)(obj, __VA_ARGS__)
#define GET_18TH_ARG(arg1, arg2, arg3, arg4, arg5, \
arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, \
arg14, arg15, arg16, arg17, arg18, ...) arg18
#define SEND_MACRO_SELECTOR(...) \
GET_18TH_ARG(__VA_ARGS__, \
SEND_ARG, SEND_ARG, SEND_ARG, SEND_ARG, SEND_ARG, \
SEND_ARG, SEND_ARG, SEND_ARG, SEND_ARG, SEND_ARG, \
SEND_ARG, SEND_ARG, SEND_ARG, SEND_ARG, SEND_ARG, \
SEND_NO_ARG, )
#define send(...) SEND_MACRO_SELECTOR(__VA_ARGS__)(__VA_ARGS__)
GNU gcc extension for ## operator prevents nested calls from being expanded, see code below.
If you're willing to use the gnu extension, here's an even more concise approach:
#define COMMAVA(...) ,##__VA_ARGS__
#define send(obj, msg, ...) find_method(obj, msg)(obj COMMAVA(__VA_ARGS__))

Collecting a list of function pointers and other ancillary data via distinct macro invocations

I want to declare a number of functions with the same signature, possibly spread across different header files, and then use the preprocessor to collect into an array pointers all such functions, and also create an an array of corresponding function names.
So, for example, assuming the common signature is int func(int x) I could have the following declarations:
FUNC(a) {
return x + x;
}
FUNC(b) {
return x >> 1;
}
FUNC(c) {
return x ^ 123;
}
... and the through some macro magic, I would end with something after preprocessing that looks like:
int a(int x) {
return x + x;
}
int b(int x) {
return x >> 1;
}
int c(int x) {
return x ^ 123;
}
typedef int (*intfunc_t)(int)
const intfunc_t func_ptrs[] = { &a, &b, &c };
const char *func_names[] = { "a", "b", "c" };
A worse version of this is possible using x-macros, but this requires a list like:
#define X_MACRO \
X(a) \
X(b) \
X(c)
This duplicates the information already encoded in the FUNC(a) definitions and makes it tough use this approach with an unknown number of functions spread across many headers, since this central list always needs to be kept in sync.
So I'm hoping there is some way to have the FUNC macro automatically generate the lists.
It doesn't have to compile-time constructed arrays as shown, either. Anything that allows me to iterate over the function pointers, and get their name and possibly other ancillary information (added via additional args to FUNC) could work, e.g., a linked list initialized at startup. You can assume all the FUNC macros appear in the same compilation unit.
While I'm not interested in gcc-specific solutions like __attribute__((constructor)).
Here is my attempt to mostly solve your problem.
It is just a minimal adaptation of the x-macros.
But the difference might just make it useable for you:
The actual functional code stays in distributed headers.
The core list only needs to be adapted to total number of such functions
(and their names, if they are not single letter alphabet),
i.e. it does not mirror the functionality.
That adapation to number of functions does not require editing the core implementation.
Here is the code, all in one "file", with hints where the files are split.
/* content of distributed header a.h */
#define FUNC_a_Implementation() \
{ \
return x+x; \
}
/* content of distributed header b.h */
#define FUNC_b_Implementation() \
{ \
return x>>1 ; \
}
/* content of distributed header c.h */
#define FUNC_c_Implementation() \
{ \
return ParCode; \
}
/* content of core editable header */
/* #include here the headers a.h, b.h c.h
potentially d.h, e.h and f.h in the future
*/
#define MAGIC_LIST(ParFlavor) \
ENTRY_##ParFlavor(a) \
ENTRY_##ParFlavor(b) \
ENTRY_##ParFlavor(c) \
/* add these when needed
ENTRY_##ParFlavor(d) \
ENTRY_##ParFlavor(e) \
ENTRY_##ParFlavor(f) \
*/
/* content of core implementation */
/* include editable core header */
#define ENTRY_Implementation(ParId) \
int Func##ParId (int x) \
FUNC_##ParId##_Implementation()
#define ENTRY_Pointer(ParId) \
&Func##ParId,
#define ENTRY_Name(ParId) \
"Func"#ParId,
MAGIC_LIST(Implementation)
const intfunc_t func_ptrs[] = {
MAGIC_LIST(Pointer)
NULL
}
const char *func_names[] = {
MAGIC_LIST(Name)
""
}
When preprocessing this, the result is:
$MinGW\bin\gcc -E macros.c
# 1 "macros.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "macros.c"
# 50 "macros.c"
int Funca (int x) { return x+x; } int Funcb (int x) { return x>>1 ; } int Funcc (int x) { return x^123; }
const intfunc_t func_ptrs[] = {
&Funca, &Funcb, &Funcc,
NULL
}
const char *func_names[] = {
"Func""a", "Func""b", "Func""c",
""
}
I added a final entry to the arrays, to avoid their intialisation ending in ",". But I think most compilers will actually allow that.
I expect compilers to replace "Func""a" with "Funca". I do not like short identifiers. If your compiler does not do as expected, remove the "Func" everywhere and require the Ids to be long enough.
Expanded macros will never have pretty indentation...
I'd have a header with a function typedef and the prototypes:
//the_header.h
typedef int intfunc_t(int); /*function not function pointer*/
intfunc_t a,b,c; /*prototypes*/
include it in each implementation file, and then have one file with:
#include "the_header.h"
const intfunc_t *func_ptrs[] = { a,b,c };
const char *func_names[] = { "a","b","c" };
While it is possible to remove the a,b,c duplication and have something like:
//the_header.h
typedef int intfunc_t(int); /*function not function pointer*/
#define FUNC a,b,c
intfunc_t FUNCS; /*prototypes*/
//collector.c
#include "the_header.h"
const intfunc_t *func_ptrs[] = { FUNCS };
const char *func_names[] = { STRINGIFY_EACH(FUNCS) };
Implementing STRINGIFY_EACH would require some dark macro magic (AFAIK), such as:
#define STRINGIFY_EACH(...) MC_foreachc(MC_str, __VA_ARGS__)
#define MC_str(_d) MC_str_impl_(_d)
#define MC_str_impl_(s) #s
#define MC_foreachc(What, ...) MC_foreachc_(MC_argc(__VA_ARGS__), What, __VA_ARGS__)
/* MC_foreachc(foo, a,b,c) foo(a), foo(b), foo(c); */
#define MC_foreachc_0( What, x, ...)
#define MC_foreachc_1( What, x, ...) What(x)
#define MC_foreachc_2( What, x, ...) What(x) , MC_expand(MC_foreachc_1( What, __VA_ARGS__))
#define MC_foreachc_3( What, x, ...) What(x) , MC_expand(MC_foreachc_2( What, __VA_ARGS__))
#define MC_foreachc_4( What, x, ...) What(x) , MC_expand(MC_foreachc_3( What, __VA_ARGS__))
#define MC_foreachc_5( What, x, ...) What(x) , MC_expand(MC_foreachc_4( What, __VA_ARGS__))
#define MC_foreachc_6( What, x, ...) What(x) , MC_expand(MC_foreachc_5( What, __VA_ARGS__))
#define MC_foreachc_7( What, x, ...) What(x) , MC_expand(MC_foreachc_6( What, __VA_ARGS__))
#define MC_foreachc_8( What, x, ...) What(x) , MC_expand(MC_foreachc_7( What, __VA_ARGS__))
#define MC_foreachc_9( What, x, ...) What(x) , MC_expand(MC_foreachc_8( What, __VA_ARGS__))
#define MC_foreachc_10( What, x, ...) What(x) , MC_expand(MC_foreachc_9( What, __VA_ARGS__))
#define MC_foreachc_11( What, x, ...) What(x) , MC_expand(MC_foreachc_10( What, __VA_ARGS__))
#define MC_foreachc_12( What, x, ...) What(x) , MC_expand(MC_foreachc_11( What, __VA_ARGS__))
#define MC_foreachc_13( What, x, ...) What(x) , MC_expand(MC_foreachc_12( What, __VA_ARGS__))
#define MC_foreachc_14( What, x, ...) What(x) , MC_expand(MC_foreachc_13( What, __VA_ARGS__))
#define MC_foreachc_15( What, x, ...) What(x) , MC_expand(MC_foreachc_14( What, __VA_ARGS__))
#define MC_foreachc_16( What, x, ...) What(x) , MC_expand(MC_foreachc_15( What, __VA_ARGS__))
#define MC_foreachc_17( What, x, ...) What(x) , MC_expand(MC_foreachc_16( What, __VA_ARGS__))
#define MC_foreachc_18( What, x, ...) What(x) , MC_expand(MC_foreachc_17( What, __VA_ARGS__))
#define MC_foreachc_19( What, x, ...) What(x) , MC_expand(MC_foreachc_18( What, __VA_ARGS__))
#define MC_foreachc_20( What, x, ...) What(x) , MC_expand(MC_foreachc_19( What, __VA_ARGS__))
#define MC_foreachc_21( What, x, ...) What(x) , MC_expand(MC_foreachc_20( What, __VA_ARGS__))
#define MC_foreachc_22( What, x, ...) What(x) , MC_expand(MC_foreachc_21( What, __VA_ARGS__))
#define MC_foreachc_23( What, x, ...) What(x) , MC_expand(MC_foreachc_22( What, __VA_ARGS__))
#define MC_foreachc_24( What, x, ...) What(x) , MC_expand(MC_foreachc_23( What, __VA_ARGS__))
#define MC_foreachc_25( What, x, ...) What(x) , MC_expand(MC_foreachc_24( What, __VA_ARGS__))
#define MC_foreachc_26( What, x, ...) What(x) , MC_expand(MC_foreachc_25( What, __VA_ARGS__))
#define MC_foreachc_27( What, x, ...) What(x) , MC_expand(MC_foreachc_26( What, __VA_ARGS__))
#define MC_foreachc_28( What, x, ...) What(x) , MC_expand(MC_foreachc_27( What, __VA_ARGS__))
#define MC_foreachc_29( What, x, ...) What(x) , MC_expand(MC_foreachc_28( What, __VA_ARGS__))
#define MC_foreachc_30( What, x, ...) What(x) , MC_expand(MC_foreachc_29( What, __VA_ARGS__))
#define MC_foreachc_31( What, x, ...) What(x) , MC_expand(MC_foreachc_30( What, __VA_ARGS__))
#define MC_foreachc_32( What, x, ...) What(x) , MC_expand(MC_foreachc_31( What, __VA_ARGS__))
#define MC_foreachc_(N, What, ...) MC_expand(MC_cat(MC_foreachc_, N)( What, __VA_ARGS__))

Macro count params

In order to make compiler happy I have to count params passed to A(), otherwise gcc raises "warning: ISO C99 requires rest arguments to be used" when pedantic flag is on and only one param is passed
#include <stdio.h>
/* Count params */
#define N_ARGS(...) N_ARGS_IMPL(__VA_ARGS__,n,n,n,n,n,n,n,n,n,1,1)
#define N_ARGS_IMPL(_0,_1,_2,_3,_4,_5,_6,_7,_8,_9,N,...) N
#define A_fmt_void
#define A_arg_void
/* link */
#define A_fmt_link_1(fmt) " href=\""fmt"\""
#define A_fmt_link_n(fmt, ...) " href=\""fmt"\""
#define A_fmt_link_N(n, ...) A_fmt_link_##n(__VA_ARGS__)
#define A_fmt_link_X(n, ...) A_fmt_link_N(n,__VA_ARGS__)
#define A_fmt_link(...) A_fmt_link_X(N_ARGS(__VA_ARGS__), __VA_ARGS__)
#define A_arg_link_1(fmt)
#define A_arg_link_n(fmt, ...) , __VA_ARGS__
#define A_arg_link_N(n, ...) A_arg_link_##n(__VA_ARGS__)
#define A_arg_link_X(n, ...) A_arg_link_N(n,__VA_ARGS__)
#define A_arg_link(...) A_arg_link_X(N_ARGS(__VA_ARGS__), __VA_ARGS__)
/* text */
#define A_fmt_text_1(fmt) fmt
#define A_fmt_text_n(fmt, ...) fmt
#define A_fmt_text_N(n, ...) A_fmt_text_##n(__VA_ARGS__)
#define A_fmt_text_X(n, ...) A_fmt_text_N(n,__VA_ARGS__)
#define A_fmt_text(...) A_fmt_text_X(N_ARGS(__VA_ARGS__), __VA_ARGS__)
#define A_arg_text_1(fmt)
#define A_arg_text_n(fmt, ...) , __VA_ARGS__
#define A_arg_text_N(n, ...) A_arg_text_##n(__VA_ARGS__)
#define A_arg_text_X(n, ...) A_arg_text_N(n,__VA_ARGS__)
#define A_arg_text(...) A_arg_text_X(N_ARGS(__VA_ARGS__), __VA_ARGS__)
/* macro */
#define A(link, text) \
printf("<a"A_fmt_##link">"A_fmt_##text"</a>\n" A_arg_##link A_arg_##text)
int main(void)
{
A(link(), void);
A(void, text());
A(link("http://www.google.es"), void);
A(link("%s/%s", "http://www.google.es", "home"), text("Visit google"));
A(void, text("%s today", "Visit google"));
A(link("http://%s/%s", "www.google.es", "home"), text("%s today", "Visit google"));
A(void,void);
return 0;
}
With this implementation of N_ARGS I can use only 10 params, is there another way to check if there is more than one param without limit in macro?
I know , ## __VA_ARGS__ gcc extension but I want to avoid warnings
Finally I've fixed using __ extension__
#include <stdio.h>
#define A_fmt_void
#define A_arg_void
#define A_fmt_link(fmt, ...) " href=\""fmt"\""
#define A_arg_link(fmt, ...) , ## __VA_ARGS__
#define A_fmt_text(fmt, ...) fmt
#define A_arg_text(fmt, ...) , ## __VA_ARGS__
#define A(link, text) \
__extension__ printf("<a" A_fmt_##link ">" A_fmt_##text "</a>\n" A_arg_##link A_arg_##text)
int main(void)
{
A(
link("%s", "http://wwww.google.com"),
text("%s", "Visit google")
);
A(
link("http://wwww.google.com"),
void
);
A(
void,
text("Visit google")
);
A(
void,
void
);
return 0;
}
This prevents warnings when pedantic flag is on :)

Resources