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++.
Related
I'm trying to generate a bunch of types off a simple template using macros to remove some of the copy and paste work this would usually require but I've ran into a bit of a problem.
These are my macros to generate the types:
#define VEC2_TYPES_LIST(X) \
X(Vec2f, float, ) \
X(Vec2d, double, ) \
X(Vec2u, uint32_t, ) \
X(Vec2i, int32_t, )
#define X_TYPE(u, t, s) \
typedef union u \
{ \
struct \
{ \
t x; \
t y; \
}; \
\
struct \
{ \
t elem[2]; \
}; \
\
s \
} u;
VEC2_TYPES_LIST(X_TYPE)
The problem is that I want to create common functions to these types that will be dynamically dispatched at runtime through a vtable. So as well as making the function definitions I also wanted to put them into a structure as function pointers. Something like this:
#define VEC2_FUNCTIONS_LIST( ?? )
X(u, u##_add, (u a, u b)) // return type, function name, params
To generate this code:
Vec2f vec2f_add(Vec2f a, Vec2f b);
...
Vec2i vec2i_add(Vec2i a, Vec2i b);
struct Vec2fVTable
{
Vec2f (*vec2f_add)(Vec2f a, Vec2f b);
};
// same for other types
I have no idea how to go about doing this so I'd appreciate if someone could teach me.
I have found a solution:
// Generate export functions and function pointers for the vtables
#define X_FUNC(ret, name, param) ACC_EXPORT ret name param;
#define X_FUNC_PTR(ret, name, param) ret (*name) param;
// Generate types
#ifdef X86_SIMD
#define VEC_TYPE_LIST(X) \
VEC_DIMENSIONS(X, f, float, __m128 simd;) \
VEC_DIMENSIONS(X, d, double, __m128d simd;) \
VEC_DIMENSIONS(X, i, int32_t, __m128i simd;) \
VEC_DIMENSIONS(X, u, uint32_t, __m128i simd;)
#else
#define VEC_TYPE_LIST(X) \
VEC_DIMENSIONS(X, f, float, ) \
VEC_DIMENSIONS(X, d, double, ) \
VEC_DIMENSIONS(X, i, int32_t, ) \
VEC_DIMENSIONS(X, u, uint32_t, )
#endif
// Generate dimensions
#define VEC_DIMENSIONS(X, suf, type, simd) \
X(suf, 2, type, simd) \
X(suf, 3, type, simd) \
X(suf, 4, type, simd)
// Generate element structs
#define VEC_ELEMENTS_STRUCT_2(type) struct { type x; type y; };
#define VEC_ELEMENTS_STRUCT_3(type) struct { type x; type y; type z; };
#define VEC_ELEMENTS_STRUCT_4(type) struct { type x; type y; type z; type w; };
// Generate functions
#define VEC_FUNCTIONS_LIST(X, funcPref, type, vecType) \
X(vecType, funcPref##_add, (vecType a, vecType b)) \
X(vecType, funcPref##_subtract, (vecType a, vecType b)) \
// Type template
#define X_VEC_TYPE(suf, dim, type, simd) \
typedef union Vec##dim##suf \
{ \
VEC_ELEMENTS_STRUCT_##dim(type) \
struct { type elements[dim]; }; \
simd \
} Vec##dim##suf; \
VEC_FUNCTIONS_LIST(X_FUNC, vec##dim##suf, type, Vec##dim##suf) \
typedef struct Vec##dim##suf##VTable \
{ \
VEC_FUNCTIONS_LIST(X_FUNC_PTR, vec##dim##suf, type, Vec##dim##suf) \
} Vec##dim##suf##VTable; \
// Generate everything
VEC_TYPE_LIST(X_VEC_TYPE)
I want to do "static dispatching" at compile-time via types.
Specifically, there is a family of functions (parameterized by type), and I want to select a function from that family (at compile-time) based on the type of an argument.
In C11, one can do this using _Generic().
For example, the following code works.
// gcc generic.c -o generic && ./generic
#include <stdio.h>
void foo_int() { printf("%s\n", __func__); } // Arbitrary code to show that this works
void foo_float() { printf("%s\n", __func__); } // Arbitrary code to show that this works
void foo_double(){ printf("%s\n", __func__); } // Arbitrary code to show that this works
#define foo_api0(VAL) \
_Generic(VAL, \
int: foo_int, \
float: foo_float, \
double: foo_double \
)()
int main(){
foo_api0(2);
foo_api0(4.f);
foo_api0(8.);
}
However, now suppose that, in the macro foo_api,
I don't want to pass a value of the desired type,
but I want to pass the desired type itself.
(The reasons why are not important for the current discussion. Assume such reasons exist.)
For example, instead of
foo_api0(2);
foo_api0(4.f);
foo_api0(8.);
I want to do
foo_api1(int);
foo_api1(float);
foo_api1(double);
One can achieve this by using the type itself to create an auxiliary variable (ie. a "witness" of the type):
#define foo_api1(TYPE) ({ \
TYPE witness; \
_Generic(witness, \
int: foo_int, \
float: foo_float, \
double: foo_double \
)(); \
})
and then both APIs work:
int main(){
foo_api0(2);
foo_api0(4.f);
foo_api0(8.);
foo_api1(int);
foo_api1(float);
foo_api1(double);
}
My question is:
Is there a way of doing this without using such an auxiliary variable?
(Perhaps there's a macro/keyword in C that can do stuff based on a type itself, rather than on a variable of that type?)
For example, it'd be nice to have something like:
#define foo_api1(TYPE) ({ \
_Generic(TYPE, \
int: foo_int, \
float: foo_float, \
double: foo_double \
)(); \
})
to pass the desired type itself.
Form a compound literal: (TYPE){0}
#define foo_api1(TYPE) \
_Generic((TYPE){0}, \
int: foo_int, \
float: foo_float, \
double: foo_double \
)()
int main(){
foo_api1(int);
foo_api1(float);
foo_api1(double);
}
To address #Eric Postpischil comment:
Form a compound literal as a pointer: (TYPE *){0}
#define foo_api2(TYPE) \
_Generic((TYPE *){0}, \
int *: foo_int, \
float *: foo_float, \
double *: foo_double \
)()
I have seen a macro ALLOW_ERROR_INJECTION which is used in SYSCALL_DEFINEx
#ifdef CONFIG_FUNCTION_ERROR_INJECTION
/*
* Whitelist ganerating macro. Specify functions which can be
* error-injectable using this macro.
*/
#define ALLOW_ERROR_INJECTION(fname, _etype) \
static struct error_injection_entry __used \
__attribute__((__section__("_error_injection_whitelist"))) \
_eil_addr_##fname = { \
.addr = (unsigned long)fname, \
.etype = EI_ETYPE_##_etype, \
};
#else
#define ALLOW_ERROR_INJECTION(fname, _etype)
#endif
#endif
Can anyone provide me enough documentation on this.
What is the use of it. What is whitelist
I'm trying to implement a generic stack in C, with the help of a big macro (not the best way, but that's not the point here).
This macro contains functions declarations, structures and functions calls, with a TYPE type that would be replaced by what needed:
#define STACK(TYPE) \
( \
struct stack \
{ \
size_t size; \
struct container *top; \
}; \
\
struct container \
{ \
TYPE data; \
struct container *next; \
}; \
\
struct stack *stack_init(void) \
{ \
struct stack *s = malloc(sizeof (struct stack)); \
if (!s) \
return NULL; \
return s; \
} \
... ...
)
This header file would be called in any .c file with this line
#include "utils_stack.h"
STACK(int)
Thing is, after trying every possible form of syntax gcc told me to try, I can't find a way to get it to work. I tried with parenthesis, brackets, both, none...
The code just simply won't work. Here is the error I get with the above syntax for example:
error: expected identifier or ‘(’ before ‘struct’
While trying to run gcc with the -E flag, I clearly see that TYPE is being replaced by int.
So here is my question, How do I need to write my macro to be able to... use it ?
Thank you in advance
As mentioned in the comment, this should work, just remove the parentheses:
#include <stdio.h>
#include <malloc.h>
#define STACK(TYPE) \
struct stack \
{ \
size_t size; \
struct container *top; \
}; \
\
struct container \
{ \
TYPE data; \
struct container *next; \
}; \
\
struct stack *stack_init(void) \
{ \
struct stack *s = malloc(sizeof (struct stack)); \
if (!s) \
return NULL; \
return s; \
} \
STACK(int)
int main()
{
struct stack *s;
s = stack_init();
// ...
}
Use parentheses if you define function-like macros, like:
#define maxint(a,b) \
({int _a = (a), _b = (b); _a > _b ? _a : _b; })
See gcc statement expresions for details.
A while ago, I wrote a set of X-macros for a largish project. I needed to maintain coherent lists of both strings and enumerated references/hash values/callback functions etc. Here is what the function callback looks like
#define LREF_LOOKUP_TABLE_TEXT_SIZE 32
#define _LREF_ENUM_LIST(_prefix,_ref,...) _prefix ## _ ## _ref,
#define _LREF_BASE_STRUCT_ENTRY(_prefix,_ref) .text= #_ref "\0", .position= _LREF_ENUM_LIST(_prefix, _ref)
#define _LREF_FUNCTION_STRUCT_LIST(_prefix,_ref,...) {_LREF_BASE_STRUCT_ENTRY(_prefix,_ref) _prefix ## _ ## _ref ## _callback},
#define _LREF_ENUM_TYPEDEF(_prefix) \
typedef enum _prefix \
{ \
_ ## _prefix ## s(_prefix,_LREF_ENUM_LIST) \
_LREF_ENUM_LIST(_prefix,tblEnd) \
} e_ ## _prefix
#define _LREF_LOOKUP_TABLE_TYPEDEF(_prefix, _extras) \
typedef struct _prefix ## _lookup \
{ \
const char text[LREF_LOOKUP_TABLE_TEXT_SIZE]; \
e_ ## _prefix position; \
_extras \
} _prefix ##_lookup_t
#define LREF_GENERIC_LOOKUP_TABLE(_prefix, _type, _tabledef, _listdef, _extras) \
_LREF_ENUM_TYPEDEF(_prefix); \
_LREF_LOOKUP_TABLE_TYPEDEF(_prefix,_tabledef); \
_extras \
_LREF_LOOKUP_TABLE_DECLARATION(_prefix,_listdef, _type)
#define LREF_FUNCTION_LOOKUP_TABLE(_prefix, _type) \
_ ## _prefix ## s(_prefix, _LREF_FUNCTION_DEF ) \
LREF_GENERIC_LOOKUP_TABLE( _prefix, \
_type, \
void* (*function) (void*);, \
_LREF_FUNCTION_STRUCT_LIST, )
This sits in a header file and allows me to write things like:
#define _cl_tags(x,_) \
_(x, command_list) \
_(x, command) \
_(x, parameter) \
_(x, fixed_parameter) \
_(x, parameter_group) \
_(x, group) \
_(x, map) \
_(x, transform)
LREF_FUNCTION_LOOKUP_TABLE(cl_tag, static);
This keeps processing routines short. For example, loading a configuration file with the above tags is simply:
for (node_tag = cl_tag_lookup_table; node_tag->position != cl_tag_tblEnd; node_tag++)
{
if (strcasecmp(test_string, node_tag->text) == 0)
{
func_return = node_tag->function((void*)m_parser);
}
}
My question is this: I hate that I have to include the second parameter in my #define. I want to be able to write #define _cl_tags(_) instead of #define _cl_tags(x,_). As you can see, the x is only used to pass the prefix (cl_tag) down. But this is superfluous as the prefix is a parameter to the initial macro.
The solution to this would be easy if my preprocessor would expand the outer-most macros first. Unfortunately, GCC's preprocessor works through the inner-most macros, i.e. parameter values, before expanding the outermost macro.
I am using gcc 4.4.5
Clarification
By C89 (and C99) standard, the following definitions
#define plus(x,y) add(y,x)
#define add(x,y) ((x)+(y))
with the invocation
plus(plus(a,b),c)
should yield
plus(plus(a,b),c)
add(c,plus(a,b))
((c)+(plus(a,b))
((c)+(add(b,a))
((c)+(((b)+(a))))
gcc 4.4.5 gives
plus(plus(a,b),c)
plus(add(b,a),c)
plus(((b)+(a)),c)
add(c,((b)+(a)))
((c)+(((b)+(a))))
Here's what I would do (have done similarly):
Put these in a utility header file:
/*
* Concatenate preprocessor tokens A and B without expanding macro definitions
* (however, if invoked from a macro, macro arguments are expanded).
*/
#define PPCAT_NX(A, B) A ## B
/*
* Concatenate preprocessor tokens A and B after macro-expanding them.
*/
#define PPCAT(A, B) PPCAT_NX(A, B)
Then define this before including your LREF macro header file:
#define LREF_TAG cl_tag
Then, in your LREF macro header file,
#define LREF_PFX(x) PPCAT(LREF_TAG, x)
#define LREF_SFX(x) PPCAT(x, LREF_TAG)
Then replace every instance of _prefix ## foo with LREF_PFX(foo) and foo ## _prefix with LREF_SFX(foo).
(When pasting more than two tokens together, just use nested PPCAT's.)
Your invocation would become
#define LREF_TAG cl_tag
#define _cl_tags(_) \
_(command_list) \
_(command) \
_(parameter) \
_(fixed_parameter) \
_(parameter_group) \
_(group) \
_(map) \
_(transform)
LREF_FUNCTION_LOOKUP_TABLE(static);
This answer just addresses the 'clarification'. Here is the correct behaviour:
#define plus(x,y) add(y,x)
#define add(x,y) ((x)+(y))
Initial: plus(plus(a,b),c)
Pass 1a: plus(add(b,a),c)
Pass 1b: add(c,add(b,a))
Pass 2a: add(c,((b)+(a)))
Pass 2b: ((c)+(((b)+(a))))
The rules are that each macro is replaced once non-recursively (starting from the inner-most when they are nested); and then a new pass (aka. "rescan") happens repeating the same procedure, this continues until a pass performs no replacement.
I'm not sure what point you were trying to make though, as you give the same final conclusion for both GCC and what you expected to happen.