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.
Related
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.
Related to this question on Software Engineering about easily serializing various struct contents on demand, I found an article which uses x-macros to create struct metadata needed for "out of the box" struct serialization. I've also seen similar techniques for "smart enums", but it boils down to the same principle, getting a string representation of an enum, or a struct's field value by its name, or something similar.
However experienced C programmers on Stack Overflow state that the x-macros should be avoided as the "last resort":
Generic enum to text lookup in C
Nested macro iteration with C preprocessor
How to access member of struct dynamically in C?
I could probably find many more related threads, but unfortunately I didn't bookmark them so this is just some Google-fu.
Perhaps the correct answer is something like Protocol Buffers? But why would creating struct definition in a different language (.proto definitions) and then running a build step to generate C files be preferable to using the built-in preprocessor for the same thing? And the issue is that these techniques still don't let me retrieve a single struct by name, I must share the same definition between two projects and keep them in sync.
So the question is then: If x-macros are "last resort", which approach for my problem (easily serializing various internal data when requested from a different device) would be "first resort", or anything before resorting to macro hell?
With a bit of preprocessor magic taken from Boost we can make a macro able to generate reflectable enums.
I managed to construct a simple proof-of-concept implementation provided below.
First, the usage. Following:
ReflEnum(MyEnum,
(first)
(second , 42)
(third)
)
Gets expanded to:
enum MyEnum
{
first,
second = 42,
third,
};
const char *EnumToString_MyEnum(enum MyEnum param)
{
switch (param)
{
case first:
return "first";
case second:
return "second";
case third:
return "third";
default:
return "<invalid>";
}
}
Thus a complete program could look like this:
#include <stdio.h>
/*
* Following is generated by the below ReflEnum():
* enum MyEnum {first, second = 42, third};
* const char *EnumToString_MyEnum(enum MyEnum value) {}
*/
ReflEnum(MyEnum,
(first)
(second , 42)
(third)
)
int main()
{
enum MyEnum foo = second;
puts(EnumToString_MyEnum(foo)); // -> "second"
puts(EnumToString_MyEnum(43)); // -> "third"
puts(EnumToString_MyEnum(9001)); // -> "<invalid>"
}
And here is the implementation itself.
It consists of two parts. The code itself and a preprocessor magic header shamelessly ripped off from Boost.
The code:
#define ReflEnum_impl_Item(...) PPUTILS_VA_CALL(ReflEnum_impl_Item_, __VA_ARGS__)(__VA_ARGS__)
#define ReflEnum_impl_Item_1(name) name,
#define ReflEnum_impl_Item_2(name, value) name = value,
#define ReflEnum_impl_Case(...) case PPUTILS_VA_FIRST(__VA_ARGS__): return PPUTILS_STR(PPUTILS_VA_FIRST(__VA_ARGS__));
#define ReflEnum(name, seq) \
enum name {PPUTILS_SEQ_APPLY(seq, ReflEnum_impl_Item)}; \
const char *EnumToString_##name(enum name param) \
{ \
switch (param) \
{ \
PPUTILS_SEQ_APPLY(seq, ReflEnum_impl_Case) \
default: return "<invalid>"; \
} \
}
It shouldn't be too hard to extend the code to support string->enum conversion; ask in the comments if you're not sure.
The magic:
Note that the preprocessor magic has to be generated by a script, and you have to choose a maximum enum size when generating it. The generation is easy and left as an exercise to the reader.
Boost defaults the size to 64, the code below was generated for size 4.
#define PPUTILS_E(...) __VA_ARGS__
#define PPUTILS_VA_FIRST(...) PPUTILS_VA_FIRST_IMPL_(__VA_ARGS__,)
#define PPUTILS_VA_FIRST_IMPL_(x, ...) x
#define PPUTILS_PARENS(...) (__VA_ARGS__)
#define PPUTILS_DEL_PARENS(...) PPUTILS_E __VA_ARGS__
#define PPUTILS_CC(a, b) PPUTILS_CC_IMPL_(a,b)
#define PPUTILS_CC_IMPL_(a, b) a##b
#define PPUTILS_CALL(macro, ...) macro(__VA_ARGS__)
#define PPUTILS_VA_SIZE(...) PPUTILS_VA_SIZE_IMPL_(__VA_ARGS__,4,3,2,1,0)
#define PPUTILS_VA_SIZE_IMPL_(i1,i2,i3,i4,size,...) size
#define PPUTILS_STR(...) PPUTILS_STR_IMPL_(__VA_ARGS__)
#define PPUTILS_STR_IMPL_(...) #__VA_ARGS__
#define PPUTILS_VA_CALL(name, ...) PPUTILS_CC(name, PPUTILS_VA_SIZE(__VA_ARGS__))
#define PPUTILS_SEQ_CALL(name, seq) PPUTILS_CC(name, PPUTILS_SEQ_SIZE(seq))
#define PPUTILS_SEQ_DEL_FIRST(seq) PPUTILS_SEQ_DEL_FIRST_IMPL_ seq
#define PPUTILS_SEQ_DEL_FIRST_IMPL_(...)
#define PPUTILS_SEQ_FIRST(seq) PPUTILS_DEL_PARENS(PPUTILS_VA_FIRST(PPUTILS_SEQ_FIRST_IMPL_ seq,))
#define PPUTILS_SEQ_FIRST_IMPL_(...) (__VA_ARGS__),
#define PPUTILS_SEQ_SIZE(seq) PPUTILS_CC(PPUTILS_SEQ_SIZE_0 seq, _VAL)
#define PPUTILS_SEQ_SIZE_0(...) PPUTILS_SEQ_SIZE_1
#define PPUTILS_SEQ_SIZE_1(...) PPUTILS_SEQ_SIZE_2
#define PPUTILS_SEQ_SIZE_2(...) PPUTILS_SEQ_SIZE_3
#define PPUTILS_SEQ_SIZE_3(...) PPUTILS_SEQ_SIZE_4
#define PPUTILS_SEQ_SIZE_4(...) PPUTILS_SEQ_SIZE_5
// Generate PPUTILS_SEQ_SIZE_i
#define PPUTILS_SEQ_SIZE_0_VAL 0
#define PPUTILS_SEQ_SIZE_1_VAL 1
#define PPUTILS_SEQ_SIZE_2_VAL 2
#define PPUTILS_SEQ_SIZE_3_VAL 3
#define PPUTILS_SEQ_SIZE_4_VAL 4
// Generate PPUTILS_SEQ_SIZE_i_VAL
#define PPUTILS_SEQ_APPLY(seq, macro) PPUTILS_SEQ_CALL(PPUTILS_SEQ_APPLY_, seq)(macro, seq)
#define PPUTILS_SEQ_APPLY_0(macro, seq)
#define PPUTILS_SEQ_APPLY_1(macro, seq) PPUTILS_CALL(macro, PPUTILS_SEQ_FIRST(seq))
#define PPUTILS_SEQ_APPLY_2(macro, seq) PPUTILS_CALL(macro, PPUTILS_SEQ_FIRST(seq)) PPUTILS_SEQ_CALL(PPUTILS_SEQ_APPLY_, PPUTILS_SEQ_DEL_FIRST(seq))(macro, PPUTILS_SEQ_DEL_FIRST(seq))
#define PPUTILS_SEQ_APPLY_3(macro, seq) PPUTILS_CALL(macro, PPUTILS_SEQ_FIRST(seq)) PPUTILS_SEQ_CALL(PPUTILS_SEQ_APPLY_, PPUTILS_SEQ_DEL_FIRST(seq))(macro, PPUTILS_SEQ_DEL_FIRST(seq))
#define PPUTILS_SEQ_APPLY_4(macro, seq) PPUTILS_CALL(macro, PPUTILS_SEQ_FIRST(seq)) PPUTILS_SEQ_CALL(PPUTILS_SEQ_APPLY_, PPUTILS_SEQ_DEL_FIRST(seq))(macro, PPUTILS_SEQ_DEL_FIRST(seq))
// Generate PPUTILS_SEQ_APPLY_i
The "first resort" would typically be one of:
Group all your data in tables made of arrays/structs, preferably read-only ones, as in the first linked example. The table index is used as the search key to keep the data together ("primary key" to use RDBMS terms). This is fast and readable, but care must be taken during maintenance.
Group your data according to some OO design. You can use opaque pointers and functions pointers to achieve private encapsulation and polymorphism. When used correctly, this can give state of the art program design. But at the same time it can be somewhat burdensome to write. And if you can't use dynamic memory allocation (embedded systems) then you have to invent a memory pool per class. Works best for more complex "ADT"-like containers and for API design.
That being said, X-macros are somewhat acceptable as long as you don't assume that every reader is familiar with them. I would therefore leave some comments about how the macro lists works, how they expand when used, and how they should be maintained.
From the linked code example, the line #define X(dir) {dir, #dir} should perhaps be commented more properly like this:
/*
Create a temporary X-macro that expands the DIRECTION_LIST, to form
an array initialization list. The format will be:
{north, "north"},
{south, "south"},
...
*/
#define X(dir) {dir, #dir}
DIRECTION_LIST
#undef X
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.
I'm trying to think of a clever way (in C) to create an array of strings, along with symbolic names (enum or #define) for the array indices, in one construct for easy maintenance. Something like:
const char *strings[] = {
M(STR_YES, "yes"),
M(STR_NO, "no"),
M(STR_MAYBE, "maybe")
};
where the result would be equivalent to:
const char *strings[] = {"yes", "no", "maybe"};
enum indices {STR_YES, STR_NO, STR_MAYBE};
(or #define STR_YES 0, etc)
but I'm drawing a blank for how to construct the M macro in this case.
Any clever ideas?
A technique used in the clang compiler source is to create .def files that contains a list like this, which is designed like a C file and can easily be maintained without touching other code files that use it. For example:
#ifndef KEYWORD
#define KEYWORD(X)
#endif
#ifndef LAST_KEYWORD
#define LAST_KEYWORD(X) KEYWORD(X)
#endif
KEYWORD(return)
KEYWORD(switch)
KEYWORD(while)
....
LAST_KEYWORD(if)
#undef KEYWORD
#undef LAST_KEYWORD
Now, what it does is including the file like this:
/* some code */
#define KEYWORD(X) #X,
#define LAST_KEYWORD(X) #X
const char *strings[] = {
#include "keywords.def"
};
#define KEYWORD(X) kw_##X,
#define LAST_KEYWORD(X) kw_##X
enum {
#include "keywords.def"
};
In your case, you could do similar. If you can live with STR_yes, STR_no, ... as enumerator names you could use the same approach like above. Otherwise, just pass the macro two things. One lowercase name and one uppercase name. Then you could stringize the one you want like above.
This is a good place to use code generation. Use a language like perl, php or whatever to generate your .h file.
It is not required to put this into specific .def files; using only the preprocessor is perfectly possible. I usually define a list named ...LIST where each element is contained within ...LIST_ELEMENT. Depending on what I will use the list for I will either just separate with a comma for all but the last entry (simplest), or in the general case make it possible to select the separator individually on each usage. Example:
#include <string.h>
#define DIRECTION_LIST \
DIRECTION_LIST_ELEMENT( up, DIRECTION_LIST_SEPARATOR ) \
DIRECTION_LIST_ELEMENT( down, DIRECTION_LIST_SEPARATOR ) \
DIRECTION_LIST_ELEMENT( right, DIRECTION_LIST_SEPARATOR ) \
DIRECTION_LIST_ELEMENT( left, NO_COMMA )
#define COMMA ,
#define NO_COMMA /**/
#define DIRECTION_LIST_ELEMENT(elem, sep) elem sep
#define DIRECTION_LIST_SEPARATOR COMMA
typedef enum {
DIRECTION_LIST
} direction_t;
#undef DIRECTION_LIST_ELEMENT
#undef DIRECTION_LIST_SEPARATOR
#define DIRECTION_LIST_ELEMENT(elem, sep) void (*move_ ## elem)(struct object_s * object);
#define DIRECTION_LIST_SEPARATOR NO_COMMA
typedef struct object_s {
char *name;
// ...
DIRECTION_LIST
} object_t;
#undef DIRECTION_LIST_ELEMENT
#undef DIRECTION_LIST_SEPARATOR
static void move(object_t *object_p, const char * direction_string)
{
if (0) {
}
#define DIRECTION_LIST_SEPARATOR NO_COMMA
#define DIRECTION_LIST_ELEMENT(elem, sep) \
else if (strcmp(direction_string, #elem) == 0) { \
object_p->move_ ## elem(object_p); \
}
DIRECTION_LIST
#undef DIRECTION_LIST_ELEMENT
#undef DIRECTION_LIST_SEPARATOR
}
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.