I want to simulate classes in c, and hide the implementation with macros, but i got unexpected expansion behaviour of the macros.
#define decl_class struct class { void *base ## ;
#define end_class } ## ; typedef struct class class ## ;
#define decl_methods struct class ## Methods {
#define method(returnType, methodName, ...) returnType (*methodName)(struct class *self, __VA_ARGS__) ## ;
#define end_methods } ## ;
#define class Integer
decl_class
int value;
decl_methods
method(int, getValue)
end_methods
end_class
#undef class
#define class Double
decl_class
double value;
decl_methods
method(double, getValue)
end_methods
end_class
#undef class
The compiler says that i am declaring twice the struct classMethods(class should be the name of the class instead). This means that "class" doesn't get replaced when i want it to. Is it even possible to do so?
Your first problem is that
#define end_methods } ## ;
is a syntax error (if the macro is expanded), because the result of the token paste is not a single valid token. You should have gotten error messages like
error: pasting "}" and ";" does not give a valid preprocessing token
Your second problem is that token pastes are executed before nested macro expansion. That means your macro
#define decl_methods struct class ## Methods {
is effectively the same as if you had written
#define decl_methods struct classMethods {
To get it to do what you want, class must be a formal parameter to a function-like macro:
#define decl_class(class) struct class {
#define end_class(class) }; typedef struct class class;
#define decl_methods(class) struct class ## Methods {
#define end_methods(class) };
#define method(class, returnType, methodName, ...) \
returnType (*methodName)(struct class *self, __VA_ARGS__);
and then
decl_class(Double)
double value;
decl_methods(Double)
method(Double, double, get_value);
end_methods(Double)
end_class(Double)
I suppose you could avoid having to repeat the name of the class in every macro invocation by having an additional set of macros that stick the class pseudo-argument in there, but (for reasons too tedious to get into here; read the "Argument Prescan" section of the GNU CPP manual very carefully) you will need two layers of nested expansion to get the effect you want:
#define decl_class__(class_) struct class_ {
#define decl_class_(class_) decl_class__(class_)
#define decl_class decl_class_(class)
#define decl_methods__(class_) struct class_ ## Methods {
#define decl_methods_(class_) decl_methods__(class_)
#define decl_methods decl_methods_(class)
/* etc */
This is technically only required when the innermost macro needs to use ## (or #) but if you're seriously going to use these macros in a real program, you should do it uniformly for all of them otherwise you'll be tearing your hair out six months later.
And after you get past all of that you will discover that your method macro doesn't work right for zero-argument methods, e.g.
#define class Integer
method(int, getValue)
either throws an error because, in standard C, ... in a macro parameter list must receive at least one argument, or it expands to a syntactically invalid declaration,
int (*getValue)(struct Integer *self, );
The only way to work around this one is to use a GNU extension:
#define method__(class_, returnType, methodName, ...) \
returnType (*methodName)(struct class_ *self, ##__VA_ARGS__);
In GNU extended C, ## in between , and __VA_ARGS__ has the special effect of causing the comma to be deleted when the ... received no arguments. (This extension was proposed for standardization about 15 years ago, but the committee wasn't interested.)
At this point I invite you to reconsider the possibility of just using C++ instead.
Related
I've met my match. I thought I could do this, but like Captain Ahab, I don't know when to call it quits. If all else fails, I'll run a Python script to generate the code, but I'm hoping there's someone out there who is as obsessed with C preprocessor macros as I am...
I'm using GCC. Given a definition like this (or any syntactic changes that would simplify things):
// M(_slot_name, _type, _arg, _accessor)
#define DEFINE_SLOTS(M) \
M(ENABLE_A, bool, ENABLE_A_BITPOS, registry_enable_a) \
M(SLEEP_TIME, uint32_t, sleep_time, registry_sleep_time) \
M(ENABLE_B, bool, ENABLE_B_BITPOS, registry_enable_b) \
M(WAKE_TIME, uint32_t, wake_time, registry_wake_time)
I want the C preprocessor to expand the above into three different things. The first one is easy (generating an enum for each _slot_name). What I'm getting tripped up on is using the _type field to conditionally generate different output.
1. An enum for each slot_name:
typedef enum {
ENABLE_A,
SLEEP_TIME,
ENABLE_B,
WAKE_TIME,
} slot_id_t;
(This one is easy - I know how to do it...)
2. An enum that only includes the slots with a bool type:
typedef enum {
ENABLE_A_BITPOS,
ENABLE_B_BITPOS,
} bitpos_t;
3. Functions whose bodies differ by the _type field:
bool registry_enable_a(void) { return foo(ENABLE_A_BITPOS); }
uint32_t registry_sleep_time(void) { return bar->sleep_time); }
bool registry_enable_b(void) { return foo(ENABLE_B_BITPOS); }
uint32_t registry_wake_time(void) { return bar->wake_time); }
Provided that the _type values are all limited to elements of a known-in-advance set and that they contain only single-token identifiers,* you can engage token pasting and some supplementary macros to achieve what you describe. Example:
// M(_slot_name, _type, _arg, _accessor)
#define DEFINE_SLOTS(M) \
M(ENABLE_A, bool, ENABLE_A_BITPOS, registry_enable_a) \
M(SLEEP_TIME, uint32_t, sleep_time, registry_sleep_time) \
M(ENABLE_B, bool, ENABLE_B_BITPOS, registry_enable_b) \
M(WAKE_TIME, uint32_t, wake_time, registry_wake_time)
#define SLOT_ENUM_VALUE(_slot_name, ...) _slot_name,
#define bool_BP_ENUM_VALUE(_arg) _arg,
#define uint32_t_BP_ENUM_VALUE(_arg) /* nothing */
#define BITPOS_ENUM_VALUE(_1, _type, _arg, _4) _type ## _BP_ENUM_VALUE(_arg)
#define bool_SLOT_FUNCTION(_slot_name, _type, _arg, _accessor) \
_type _accessor(void) { return foo(_arg); }
#define uint32_t_SLOT_FUNCTION(_slot_name, _type, _arg, _accessor) \
_type _accessor(void) { return bar->_arg; }
#define SLOT_FUNCTION(_slot_name, _type, _arg, _accessor) \
_type ## _SLOT_FUNCTION(_slot_name, _type, _arg, _accessor)
////////
typedef enum {
DEFINE_SLOTS(SLOT_ENUM_VALUE)
} slot_id_t;
typedef enum {
DEFINE_SLOTS(BITPOS_ENUM_VALUE)
} bitpos_t;
DEFINE_SLOTS(SLOT_FUNCTION)
The key here is that macro expansion does not provide for any conditional logic per se, but it does provide for treating data as code. After all, that's what the X-macro approach you were already using does. Combining that with token pasting can get you a lot more (wholly deterministic) variety in your macro expansions.
*You can use typedefs to provide single-token identifiers where necessary.
Im looking for a solution for define a struct, where the user may enable/disable struct members as in the example (pseudo-code):
#define DEF_STRUCT_1(NAME,VAL1,VAL2) \
struct my_struct_t \
{ \
#if(NAME == TRUE) \
bool name; \
#endif \
#if(VAL1 == TRUE) \
bool val1; \
#endif \
#if(VAL2 == TRUE) \
bool val2; \
#endif \
} instance1
void main() {
DEF_STRUCT_1(TRUE,FALSE,TRUE);
instance1.name = true;
//instance1.val1 = false; // error, unavailable
instance1.val2 = false;
}
I'm not sure how useful this is, but the following should do what you ask:
#define CONDITIONAL_TRUE(code) code
#define CONDITIONAL_FALSE(code)
#define DEF_STRUCT_1(NAME,VAL1,VAL2) \
struct my_struct_t \
{ \
CONDITIONAL_##NAME(bool name;) \
CONDITIONAL_##VAL1(bool val1;) \
CONDITIONAL_##VAL2(bool val2;) \
} instance1
int main() {
DEF_STRUCT_1(TRUE,FALSE,TRUE);
instance1.name = true;
//instance1.val1 = false; // error, unavailable
instance1.val2 = false;
}
All the TRUE/FALSE parameters would have to be available at compile-time. And if you want more than one version of these parameters to be used in the same program, you should make the struct name a parameter as well.
Since you say that this is intended for a library, it isn't clear how you're planning for the library code to be able to access this struct, since it would need to know which members are available. This significantly reduces the usefulness of this method.
A more common method used by libraries is to have a config.h file, editable by the library user, with definitions such as #define USE_NAME_MEMBER 1. Then you can make a normal struct definition with #if directives:
//in mylibrary.h:
#include <mylibrary_config.h>
struct my_struct_t {
#if USE_NAME_MEMBER
bool name;
#endif
/...
};
Then you would also put #if directives around any library code that accesses the name member.
Given that the struct needs to be generated differently at compile-time, given some conditions, you will be facing the problem that all code using the struct will need to be modified accordingly. Compiler switches (#ifdef FOO .... #endif) tend to scale badly with increased complexity. If there is a large number of struct members, all the needed compiler switches will make a horrible, unmaintainable mess out of the program.
There is a well-known design pattern known as "X macros", that can be used to centralize maintenance in programs to one single place, as well as allowing compile-time iteration of all items involved. They make the code hard to read too, and therefore they are a bit of a last resort. But they are a bit of de facto standard and their ugliness doesn't scale with complexity, so they are preferred over some compiler switch madness. It goes like this:
#define INSTANCE_LIST \
/* name, type */ \
X(name, bool) \
X(val1, bool) \
X(val2, bool) \
typedef struct
{
#define X(name, type) type name;
INSTANCE_LIST
#undef X
} instance_t;
This code gets pre-processed into:
typedef struct
{
bool name;
bool val1;
bool val2;
} instance_t;
The only part that needs to be maintained is the "INSTANCE_LIST". By commenting out a line in the list, that struct member will go away. This means that all code using the struct has to be using the same list accordingly. For example, lets add code to the same example, that lists the init values of each member and then sets them:
#include <stdbool.h>
#include <stdio.h>
#define INSTANCE_LIST \
/* name, type, init */ \
X(name, bool, true) \
X(val1, bool, false) \
X(val2, bool, false) \
typedef struct
{
#define X(name, type, init) type name;
INSTANCE_LIST
#undef X
} instance_t;
int main (void)
{
instance_t inst;
#define X(name, type, init) inst.name = init;
INSTANCE_LIST
#undef X
printf("%d ", inst.name);
printf("%d ", inst.val1);
printf("%d ", inst.val2);
}
Very flexible and maintainable - you can easily add more struct members without changing any other macro than the list. But as mentioned, the down-side is that the code looks quite cryptic, especially to those who aren't used to this design pattern.
I'm using X Macros in my project, so as to not repeat myself in places where a list of names all need to have identical operations performed on them (such as creation, initialization, population, and destruction).
As the data I'm trying to specify once involves a few of the same macro-able translations (ignoring arguments, prefixing vs. suffixing), I decided to enhance my original single-fit X Macros by rewriting them as generalized Meta X-Macros, from which multiple derivative end-use-case-fitting X Macros could be defined, using transformation macros that interpret the meta-macro's arguments:
// Meta-macros //
#define MAIN_WINDOW_TEXT_LAYERS_METAMACRO(macro, tr) \
macro(tr(hour_layer)) \
macro(tr(min_layer)) \
macro(tr(date_layer))
#define MAIN_WINDOW_LAYERS_METAMACRO(macro, tr) \
macro(tr(colon_layer)) \
macro(tr(phone_batt_layer)) \
macro(tr(watch_batt_layer))
#define GBITMAPS_WITH_RESOURCE_IDS_METAMACRO(macro, tr) \
macro(tr(watch_icon, ICON_WATCH_6X11)) \
macro(tr(watch_charging_icon, ICON_WATCH_CHARGING_6X11)) \
macro(tr(phone_icon, ICON_PHONE_6X11)) \
macro(tr(phone_charging_icon, ICON_PHONE_CHARGING_6X11))
#define GFONTS_WITH_RESOURCE_IDS_METAMACRO(macro, tr) \
macro(tr(time_font, FONT_ARVO_BOLD_48)) \
macro(tr(date_font, FONT_ARVO_BOLD_20))
// Transformation macros //
#define IDENTITY_MACRO(x) x
#define STATIC_PREFIX_MACRO(x) s_ ## x
#define STATIC_PREFIX_DISCARD_MACRO(x, _) s_ ## x
#define STATIC_PREFIX_RESOURCE_ID_PREFIX_MACRO(x, id) \
s_ ## x, RESOURCE_ID_ ## s
// Derived X-Macros //
#define FOR_MAIN_WINDOW_STATIC_TEXT_LAYER_POINTERS(macro) \
MAIN_WINDOW_TEXT_LAYERS_METAMACRO(macro, STATIC_PREFIX_MACRO)
#define FOR_MAIN_WINDOW_STATIC_LAYER_POINTERS(macro) \
MAIN_WINDOW_LAYERS_METAMACRO(macro, STATIC_PREFIX_MACRO)
#define FOR_MAIN_WINDOW_LAYER_NAMES(macro) \
MAIN_WINDOW_LAYERS_METAMACRO(macro, IDENTITY_MACRO)
#define FOR_STATIC_GFONTS(macro) \
GFONTS_WITH_RESOURCE_IDS_METAMACRO(macro, STATIC_PREFIX_DISCARD_MACRO)
#define FOR_STATIC_GFONTS_WITH_RESOURCE_IDS(macro) \
GFONTS_WITH_RESOURCE_IDS_METAMACRO(macro, STATIC_PREFIX_RESOURCE_ID_PREFIX_MACRO)
#define FOR_STATIC_GBITMAP_POINTERS_WITH_RESOURCE_IDS(macro) \
GBITMAPS_WITH_RESOURCE_IDS_METAMACRO(macro, STATIC_PREFIX_RESOURCE_ID_PREFIX_MACRO)
#define FOR_STATIC_GBITMAP_POINTERS(macro) \
GBITMAPS_WITH_RESOURCE_IDS_METAMACRO(macro, STATIC_PREFIX_DISCARD_MACRO)
This works, in most use cases: however, there are a few edge cases where I run into trouble. Firstly, trying to concatenate arguments results in the transformation macro's name getting concatenated, rather than the transformed name:
#define X(name) layer_set_update_proc(s_ ## name, name ## _update_proc);
FOR_MAIN_WINDOW_LAYER_NAMES(X)
#undef X
error: implicit declaration of function 's_IDENTITY_MACRO'
Secondly, macros that transform two arguments aren't getting expanded - they're being passed to X as a single token (the call to the transformation macro):
#define X(name, id) name = fonts_load_custom_font(resource_get_handle(id));
FOR_STATIC_GFONTS_WITH_RESOURCE_IDS(X)
#undef X
error: macro "X" requires 2 arguments, but only 1 given
error: unknown type name 'X'
#define X(name, id) name = gbitmap_create_with_resource(id);
FOR_STATIC_GBITMAP_POINTERS_WITH_RESOURCE_IDS(X)
#undef X
error: macro "X" requires 2 arguments, but only 1 given
error: expected '=', ',', ';', 'asm' or '__attribute__' before 'X'
How can I make these work the way I want them to?
As alluded to in other Stack Overflow questions about the C Preprocessor, the first problem (of the macro's identifier being concatenated rather than its content) can be avoided by introducing another layer of indirect evaulation to the macro:
#define X_(name) layer_set_update_proc(s_ ## name, name ## _update_proc);
#define X(name) X_(name)
FOR_MAIN_WINDOW_LAYER_NAMES(X)
#undef X
#undef X_
The second issue is more insidious, but it has a similar solution: another layer of indirection. The key trick here is that, rather than copying the signature of the final macro, the first layer must take a single argument to pass to the next layer, which will then be expanded out to multiple arguments:
#define X_(name, id) name = fonts_load_custom_font(resource_get_handle(id));
#define X(args) X_(args)
FOR_STATIC_GFONTS_WITH_RESOURCE_IDS(X)
#undef X
#undef X_
Of course, offloading these sorts of workarounds to the point-of-use, rather than fixing them at the point where they're defined, is not robust engineering, so one ought to define this layer of indirection as part of the meta-macro itself:
#define APPLY_MACRO(x, t) x(t)
#define MAIN_WINDOW_TEXT_LAYERS_METAMACRO(X, tr) \
APPLY_MACRO(X,tr(hour_layer)) \
APPLY_MACRO(X,tr(min_layer)) \
APPLY_MACRO(X,tr(date_layer))
/* etc... */
Note, however, that whatever token you choose to use for APPLY_MACRO, unlike an identifier like X or X_ that can be #defined and immediately #undefined right around the point of invocation, the indirection macro used here must remain defined for as long as these macros themselves may be used (obviously), so one should pick a name that isn't liable to cause conflicts with other portions of the codebase (ie, not just X_). Even something like APPLY_MACRO, as I used here, isn't particularly advisable: larger projects (especially any code that may be redistributed for use in other solutions) should consider prefixing the name used with some sort of namespace prefix to limit its scope from interfering with other contexts (as described in this SoftwareEngineering.se answer).
Ultimately, though, for my purposes, I ended up solving this problem by re-writing my transformation macros to take the macro to apply and call it with the transformed arguments, flattening the interpretation and allowing me to refactor out the APPLY_MACRO macro described above altogether.
I am delighted by C11's _Generic mechanism - switching on type is something I miss from C++. It is however proving difficult to compose.
For an example, given functions:
bool write_int(int);
bool write_foo(foo);
bool write_bar(bar);
// bool write_unknown is not implemented
I can then write
#define write(X) _Generic((X), \
int : write_int, \
foo: write_foo, \
bar: write_bar, \
default: write_unknown)(X)
and, provided I don't try to use &write or pass it to a function, I can call write(obj) and, provided obj is an instance of one of those types, all is well.
However, in general foo and bar are entirely unrelated to each other. They are defined in different headers, rarely (but occasionally) used together in a single source file. Where then should the macro expanding to the _Generic be written?
At present, I am accumulating header files called things like write.h, equal.h, copy.h, move.h each of which contains a set of function prototypes and a single _Generic. This is workable, but not brilliant. I don't like the requirement to collect together a list of every type in the program in a single place.
I would like to be able to define type foo in a header file, along with the function write_foo, and somehow have the client code able to call the 'function' write. Default looks like a vector through which this could be achieved.
The closest match I can find on this site is c11 generic adding types which has a partial solution, but it's not quite enough for me to see how to combine the various macros.
Let's say that, somewhere in a header file that defines write_bar, we have an existing macro definition:
#define write(x) _Generic((x), bar: write_bar, default: some_magic_here)(x)
Or we could omit the trailing (x)
#define write_impl(x) _Generic((x), bar: write_bar, default: some_magic_here)
Further down in this header, I would like a version of write() that handles either foo or bar. I think it needs to call the existing macro in its default case, but I don't believe the preprocessor is able to rename the existing write macro. If it were able to, the following could work:
#ifndef WRITE_3
#define WRITE_3(X) write(x)
#undef write(x)
#define write(x) __Generic((x),foo: write_foo,default: WRITE_3)(x)
Having just typed that out I can sort-of see a path forward:
// In bar.h
#ifndef WRITE_1
#define WRITE_1(x) __Generic((x), bar: write_bar)
#elif !defined(WRITE_2)
#define WRITE_2(x) __Generic((x), bar: write_bar)
#elif !defined(WRITE_3)
#define WRITE_3(x) __Generic((x), bar: write_bar)
#endif
// In foo.h
#ifndef WRITE_1
#define WRITE_1(x) __Generic((x), foo: write_foo)
#elif !defined(WRITE_2)
#define WRITE_2(x) __Generic((x), foo: write_foo)
#elif !defined(WRITE_3)
#define WRITE_3(x) __Generic((x), foo: write_foo)
#endif
// In write.h, which unfortunately needs to be included after the other two
// but happily they can be included in either order
#ifdef WRITE_2
#define write(x) WRITE_1(x) WRITE_2(x) (x)
#elif
// etc
#endif
This doesn't actually work though, since I can't find a way to make WRITE_N(x) expand to nothing when x doesn't match the argument list. I see the error
controlling expression type 'struct foo' not compatible with any generic association type
Or
expected expression // attempting to present an empty default clause
I believe to distribute the write() definition between several files | macros I need to work around either of the above. A _Generic clause which reduces to nothing in the default case would work, as would one which reduces to nothing if none of the types match.
Getting yet more hackish, if the functions take a pointer to a struct instead of an instance of one, and I provide write_void(void*x) {(void)x;} as the default option, then the code does compile and run. However, expanding write as
write(x) => write_void(x); write_foo(x); write_void(x);
is clearly pretty bad in itself, plus I don't really want to pass everything by pointer.
So - can anyone see a way to define a single _Generic 'function' incrementally, i.e. without starting with a list of all types it will map over? Thank you.
The need for type-generic functions across multiple, unrelated files suggests that the program design is poor.
Either those files are related and should share a common parent ("abstract base class") where the type-generic macros and function declarations can then be stated.
Or they are unrelated, but share some common method for whatever reason, in which case you need to invent a common, generic abstraction layer interface which they can then implement. You should always consider the program design on a system level the first thing you do.
This answer does not use _Generic, but proposes a different program design entirely.
To take the example from a comment, with bool equal(T lhs, T rhs). That's the latter of the above two cases, a common interface shared by multiple modules. The first thing to observe is that this is a functor, a function which can be used in turn by generic algorithms such as search/sort algorithms. The C standard suggests how functors should preferably be written:
int compare (const void* p1, const void* p2)
This is the format used by standard functions bsearch and qsort. Unless you have good reasons, you shouldn't deviate from that format, because if you don't, you'll get searching & sorting for free. Also, this form has the advantage of doing lesser, greater and equal checks all in the same function.
The classic C way to implement a common interface for such a function in C would be a header containing this macro:
Interface header:
#define compare(type, x, y) (compare_ ## type(x, y))
Module that implements the header:
// int.c
int compare_int (const void* p1, const void* p2)
{
return *(int*)p1 - *(int*)p2;
}
Caller:
if( compare(int, a, b) == 0 )
{
// equal
}
This has the advantage of abstraction: the interface header file doesn't need to know all the types used. The disadvantage is that there is no type safety what-so-ever.
(But this is C, you'll never get 100% type safety through the compiler. Use static analysis if it is a big concern.)
With C11 you can improve type safety somewhat by introducing a _Generic macro. There's a big problem with that though: that macro has to know about all existing types in advance, so you can't put it in an abstract interface header. Rather, it should not be in a common header because then you'll create a tight coupling between every single, unrelated module using that header. You could make such a macro in the calling application, not to define an interface, but to ensure type safety.
What you could do instead, is to enforce an interface through inheritance of an abstract base class:
// interface.h
typedef int compare_t (const void* p1, const void* p2);
typedef struct data_t data_t; // incomplete type
typedef struct
{
compare_t* compare;
data_t* data;
} interface_t;
The module that inherits the interface sets the compare function pointer to point at the specific comparison function, upon object creation. data is private to the module and could be anything. Suppose we create a module called "xy" that inherits the above interface:
//xy.c
struct data_t
{
int x;
int y;
};
static int compare_xy (const void* p1, const void* p2)
{
// compare an xy object in some meaningful way
}
void xy_create (interface_t* inter, int x, int y)
{
inter->data = malloc(sizeof(data_t));
assert(inter->data != NULL);
inter->compare = compare_xy;
inter->data->x = x;
inter->data->y = y;
}
A caller can then work with the generic interface_t and call the compare member. We've achieved polymorphism, as the type-specific compare function will then get called.
Based loosely on Leushenko's answer to multiparameter generics I have come up with the following horrible solution. It requires that the arguments will be passed by pointer, and the boilerplate involved is pretty bad. It does compile and run though, in a fashion which allows functions to return a value.
// foo.h
#ifndef FOO
#define FOO
#include <stdio.h>
#include <stdbool.h>
struct foo
{
int a;
};
static inline int write_foo(struct foo* f)
{
(void)f;
return printf("Writing foo\n");
}
#if !defined(WRITE_1)
#define WRITE_1
#define WRITE_PRED_1(x) _Generic((x), struct foo * : true, default : false)
#define WRITE_CALL_1(x) \
_Generic((x), struct foo * \
: write_foo((struct foo*)x), default \
: write_foo((struct foo*)0))
#elif !defined(WRITE_2)
#define WRITE_2
#define WRITE_PRED_2(x) _Generic((x), struct foo * : true, default : false)
#define WRITE_CALL_2(x) \
_Generic((x), struct foo * \
: write_foo((struct foo*)x), default \
: write_foo((struct foo*)0))
#elif !defined(WRITE_3)
#define WRITE_3
#define WRITE_PRED_3(x) _Generic((x), struct foo * : true, default : false)
#define WRITE_CALL_3(x) \
_Generic((x), struct foo * \
: write_foo((struct foo*)x), default \
: write_foo((struct foo*)0))
#endif
#endif
// bar.h
#ifndef BAR
#define BAR
#include <stdio.h>
#include <stdbool.h>
struct bar
{
int a;
};
static inline int write_bar(struct bar* b)
{
(void)b;
return printf("Writing bar\n");
}
#if !defined(WRITE_1)
#define WRITE_1
#define WRITE_PRED_1(x) _Generic((x), struct bar * : true, default : false)
#define WRITE_CALL_1(x) \
_Generic((x), struct bar * \
: write_bar((struct bar*)x), default \
: write_bar((struct bar*)0))
#elif !defined(WRITE_2)
#define WRITE_2
#define WRITE_PRED_2(x) _Generic((x), struct bar * : true, default : false)
#define WRITE_CALL_2(x) \
_Generic((x), struct bar * \
: write_bar((struct bar*)x), default \
: write_bar((struct bar*)0))
#elif !defined(WRITE_3)
#define WRITE_3
#define WRITE_PRED_3(x) _Generic((x), struct bar * : true, default : false)
#define WRITE_CALL_3(x) \
_Generic((x), struct bar * \
: write_bar((struct bar*)x), default \
: write_bar((struct bar*)0))
#endif
#endif
// write.h
#ifndef WRITE
#define WRITE
#if defined(WRITE_3)
#define write(x) \
WRITE_PRED_1(x) ? WRITE_CALL_1(x) : WRITE_PRED_2(x) ? WRITE_CALL_2(x) \
: WRITE_CALL_3(x)
#elif defined(WRITE_2)
#define write(x) WRITE_PRED_1(x) ? WRITE_CALL_1(x) : WRITE_CALL_2(x)
#elif defined(WRITE_1)
#define write(x) WRITE_CALL_1(x)
#else
#error "Write not defined"
#endif
#endif
// main.c
#include "foo.h"
#include "bar.h"
#include "write.h"
int main()
{
struct foo f;
struct bar b;
int fi = write(&f);
int bi = write(&b);
return fi + bi;
}
I really hope there's a better way than this.
I'm tidying up some older code that uses 'magic numbers' all over the place to set hardware registers, and I would like to use constants instead of these numbers to make the code somewhat more expressive (in fact they will map to the names/values used to document the registers).
However, I'm concerned that with the volume of changes I might break the magic numbers. Here is a simplified example (the register set is more complex):
const short mode0 = 0;
const short mode1 = 1;
const short mode2 = 2;
const short state0 = 0;
const short state1 = 4;
const short state2 = 8;
so instead of :
set_register(5);
we have:
set_register(state1|mode1);
What I'm looking for is a build time version of:
ASSERT(5==(state1|mode1));
Update
#Christian, thanks for the quick response, I'm interested on a C / non-boost environment answer too because this is driver/kernel code.
NEW ANSWER :
In my original answer (below), I had to have two different macros to support assertions in a function scope and at the global scope. I wondered if it was possible to come up with a single solution that would work in both scopes.
I was able to find a solution that worked for Visual Studio and Comeau compilers using extern character arrays. But I was able to find a more complex solution that works for GCC. But GCC's solution doesn't work for Visual Studio. :( But adding a '#ifdef __ GNUC __', it's easy to choose the right set of macros for a given compiler.
Solution:
#ifdef __GNUC__
#define STATIC_ASSERT_HELPER(expr, msg) \
(!!sizeof \ (struct { unsigned int STATIC_ASSERTION__##msg: (expr) ? 1 : -1; }))
#define STATIC_ASSERT(expr, msg) \
extern int (*assert_function__(void)) [STATIC_ASSERT_HELPER(expr, msg)]
#else
#define STATIC_ASSERT(expr, msg) \
extern char STATIC_ASSERTION__##msg[1]; \
extern char STATIC_ASSERTION__##msg[(expr)?1:2]
#endif /* #ifdef __GNUC__ */
Here are the error messages reported for STATIC_ASSERT(1==1, test_message); at line 22 of test.c:
GCC:
line 22: error: negative width in bit-field `STATIC_ASSERTION__test_message'
Visual Studio:
test.c(22) : error C2369: 'STATIC_ASSERTION__test_message' : redefinition; different subscripts
test.c(22) : see declaration of 'STATIC_ASSERTION__test_message'
Comeau:
line 22: error: declaration is incompatible with
"char STATIC_ASSERTION__test_message[1]" (declared at line 22)
ORIGINAL ANSWER :
I do something very similar to what Checkers does. But I include a message that'll show up in many compilers:
#define STATIC_ASSERT(expr, msg) \
{ \
char STATIC_ASSERTION__##msg[(expr)?1:-1]; \
(void)STATIC_ASSERTION__##msg[0]; \
}
And for doing something at the global scope (outside a function) use this:
#define GLOBAL_STATIC_ASSERT(expr, msg) \
extern char STATIC_ASSERTION__##msg[1]; \
extern char STATIC_ASSERTION__##msg[(expr)?1:2]
There is an article by
Ralf Holly that examines different options for static asserts in C.
He presents three different approaches:
switch case values must be unique
arrays must not have negative dimensions
division by zero for constant expressions
His conclusion for the best implementation is this:
#define assert_static(e) \
do { \
enum { assert_static__ = 1/(e) }; \
} while (0)
Checkout boost's static assert
You can roll your own static assert if you don't have access to a third-party library static assert function (like boost):
#define STATIC_ASSERT(x) \
do { \
const static char dummy[(x)?1:-1] = {0};\
} while(0)
The downside is, of course, that error message is not going to be very helpful, but at least, it will give you the line number.
#define static_assert(expr) \
int __static_assert(int static_assert_failed[(expr)?1:-1])
It can be used anywhere, any times.
I think it is the easiest solution.
Before usage, test it with your compiler carefully.
Any of the techniques listed here should work and when C++0x becomes available you will be able to use the built-in static_assert keyword.
If you have Boost then using BOOST_STATIC_ASSERT is the way to go. If you're using C or don't want to get Boost
here's my c_assert.h file that defines (and explains the workings of) a few macros to handle static assertions.
It's a bit more convoluted that it should be because in ANSI C code you need 2 different macros - one that can work in the area where you have declarations and one that can work in the area where normal statements go. There is a also a bit of work that goes into making the macro work at global scope or in block scope and a bunch of gunk to ensure that there are no name collisions.
STATIC_ASSERT() can be used in the variable declaration block or global scope.
STATIC_ASSERT_EX() can be among regular statements.
For C++ code (or C99 code that allow declarations mixed with statements) STATIC_ASSERT() will work anywhere.
/*
Define macros to allow compile-time assertions.
If the expression is false, an error something like
test.c(9) : error XXXXX: negative subscript
will be issued (the exact error and its format is dependent
on the compiler).
The techique used for C is to declare an extern (which can be used in
file or block scope) array with a size of 1 if the expr is TRUE and
a size of -1 if the expr is false (which will result in a compiler error).
A counter or line number is appended to the name to help make it unique.
Note that this is not a foolproof technique, but compilers are
supposed to accept multiple identical extern declarations anyway.
This technique doesn't work in all cases for C++ because extern declarations
are not permitted inside classes. To get a CPP_ASSERT(), there is an
implementation of something similar to Boost's BOOST_STATIC_ASSERT(). Boost's
approach uses template specialization; when expr evaluates to 1, a typedef
for the type
::interslice::StaticAssert_test< sizeof( ::interslice::StaticAssert_failed<true>) >
which boils down to
::interslice::StaticAssert_test< 1>
which boils down to
struct StaticAssert_test
is declared. If expr is 0, the compiler will be unable to find a specialization for
::interslice::StaticAssert_failed<false>.
STATIC_ASSERT() or C_ASSERT should work in either C or C++ code (and they do the same thing)
CPP_ASSERT is defined only for C++ code.
Since declarations can only occur at file scope or at the start of a block in
standard C, the C_ASSERT() or STATIC_ASSERT() macros will only work there. For situations
where you want to perform compile-time asserts elsewhere, use C_ASSERT_EX() or
STATIC_ASSERT_X() which wrap an enum declaration inside it's own block.
*/
#ifndef C_ASSERT_H_3803b949_b422_4377_8713_ce606f29d546
#define C_ASSERT_H_3803b949_b422_4377_8713_ce606f29d546
/* first some utility macros to paste a line number or counter to the end of an identifier
* this will let us have some chance of generating names that are unique
* there may be problems if a static assert ends up on the same line number in different headers
* to avoid that problem in C++ use namespaces
*/
#if !defined( PASTE)
#define PASTE2( x, y) x##y
#define PASTE( x, y) PASTE2( x, y)
#endif /* PASTE */
#if !defined( PASTE_LINE)
#define PASTE_LINE( x) PASTE( x, __LINE__)
#endif /* PASTE_LINE */
#if!defined( PASTE_COUNTER)
#if (_MSC_VER >= 1300) /* __COUNTER__ introduced in VS 7 (VS.NET 2002) */
#define PASTE_COUNTER( x) PASTE( x, __COUNTER__) /* __COUNTER__ is a an _MSC_VER >= 1300 non-Ansi extension */
#else
#define PASTE_COUNTER( x) PASTE( x, __LINE__) /* since there's no __COUNTER__ use __LINE__ as a more or less reasonable substitute */
#endif
#endif /* PASTE_COUNTER */
#if __cplusplus
extern "C++" { // required in case we're included inside an extern "C" block
namespace interslice {
template<bool b> struct StaticAssert_failed;
template<> struct StaticAssert_failed<true> { enum {val = 1 }; };
template<int x> struct StaticAssert_test { };
}
}
#define CPP_ASSERT( expr) typedef ::interslice::StaticAssert_test< sizeof( ::interslice::StaticAssert_failed< (bool) (expr) >) > PASTE_COUNTER( IntersliceStaticAssertType_)
#define STATIC_ASSERT( expr) CPP_ASSERT( expr)
#define STATIC_ASSERT_EX( expr) CPP_ASSERT( expr)
#else
#define C_ASSERT_STORAGE_CLASS extern /* change to typedef might be needed for some compilers? */
#define C_ASSERT_GUID 4964f7ac50fa4661a1377e4c17509495 /* used to make sure our extern name doesn't collide with something else */
#define STATIC_ASSERT( expr) C_ASSERT_STORAGE_CLASS char PASTE( PASTE( c_assert_, C_ASSERT_GUID), [(expr) ? 1 : -1])
#define STATIC_ASSERT_EX(expr) do { enum { c_assert__ = 1/((expr) ? 1 : 0) }; } while (0)
#endif /* __cplusplus */
#if !defined( C_ASSERT) /* C_ASSERT() might be defined by winnt.h */
#define C_ASSERT( expr) STATIC_ASSERT( expr)
#endif /* !defined( C_ASSERT) */
#define C_ASSERT_EX( expr) STATIC_ASSERT_EX( expr)
#ifdef TEST_IMPLEMENTATION
C_ASSERT( 1 < 2);
C_ASSERT( 1 < 2);
int main( )
{
C_ASSERT( 1 < 2);
C_ASSERT( 1 < 2);
int x;
x = 1 + 4;
C_ASSERT_EX( 1 < 2);
C_ASSERT_EX( 1 < 2);
return( 0);
}
#endif /* TEST_IMPLEMENTATION */
#endif /* C_ASSERT_H_3803b949_b422_4377_8713_ce606f29d546 */
Try:
#define STATIC_ASSERT(x, error) \
do { \
static const char error[(x)?1:-1];\
} while(0)
Then you can write:
STATIC_ASSERT(a == b, a_not_equal_to_b);
Which may give you a better error message (depending on your compiler).
The common, portable option is
#if 5 != (state1|mode1)
# error "aaugh!"
#endif
but it doesn't work in this case, because they're C constants and not #defines.
You can see the Linux kernel's BUILD_BUG_ON macro for something that handles your case:
#define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)]))
When condition is true, this becomes ((void)sizeof(char[-1])), which is illegal and should fail at compile time, and otherwise it becomes ((void)sizeof(char[1])), which is just fine.
Ensure you compile with a sufficiently recent compiler (e.g. gcc -std=c11).
Then your statement is simply:
_Static_assert(state1|mode1 == 5, "Unexpected change of bitflags");
#define MODE0 0
#define MODE1 1
#define MODE2 2
#define STATE0 0
#define STATE1 4
#define STATE2 8
set_register(STATE1|STATE1); //set_register(5);
#if (!(5==(STATE1|STATE1))) //MY_ASSERT(5==(state1|mode1)); note the !
#error "error blah blah"
#endif
This is not as elegant as a one line MY_ASSERT(expr) solution. You could use sed, awk, or m4 macro processor before compiling your C code to generate the DEBUG code expansion of MY_ASSERT(expr) to multiple lines or NODEBUG code which removes them for production.