I just learned of X-Macros. What real-world uses of X-Macros have you seen? When are they the right tool for the job?
I discovered X-macros a couple of years ago when I started making use of function pointers in my code. I am an embedded programmer and I use state machines frequently. Often I would write code like this:
/* declare an enumeration of state codes */
enum{ STATE0, STATE1, STATE2, ... , STATEX, NUM_STATES};
/* declare a table of function pointers */
p_func_t jumptable[NUM_STATES] = {func0, func1, func2, ... , funcX};
The problem was that I considered it very error prone to have to maintain the ordering of my function pointer table such that it matched the ordering of my enumeration of states.
A friend of mine introduced me to X-macros and it was like a light-bulb went off in my head. Seriously, where have you been all my life x-macros!
So now I define the following table:
#define STATE_TABLE \
ENTRY(STATE0, func0) \
ENTRY(STATE1, func1) \
ENTRY(STATE2, func2) \
...
ENTRY(STATEX, funcX) \
And I can use it as follows:
enum
{
#define ENTRY(a,b) a,
STATE_TABLE
#undef ENTRY
NUM_STATES
};
and
p_func_t jumptable[NUM_STATES] =
{
#define ENTRY(a,b) b,
STATE_TABLE
#undef ENTRY
};
as a bonus, I can also have the pre-processor build my function prototypes as follows:
#define ENTRY(a,b) static void b(void);
STATE_TABLE
#undef ENTRY
Another usage is to declare and initialize registers
#define IO_ADDRESS_OFFSET (0x8000)
#define REGISTER_TABLE\
ENTRY(reg0, IO_ADDRESS_OFFSET + 0, 0x11)\
ENTRY(reg1, IO_ADDRESS_OFFSET + 1, 0x55)\
ENTRY(reg2, IO_ADDRESS_OFFSET + 2, 0x1b)\
...
ENTRY(regX, IO_ADDRESS_OFFSET + X, 0x33)\
/* declare the registers (where _at_ is a compiler specific directive) */
#define ENTRY(a, b, c) volatile uint8_t a _at_ b:
REGISTER_TABLE
#undef ENTRY
/* initialize registers */
#define ENTRY(a, b, c) a = c;
REGISTER_TABLE
#undef ENTRY
My favourite usage however is when it comes to communication handlers
First I create a comms table, containing each command name and code:
#define COMMAND_TABLE \
ENTRY(RESERVED, reserved, 0x00) \
ENTRY(COMMAND1, command1, 0x01) \
ENTRY(COMMAND2, command2, 0x02) \
...
ENTRY(COMMANDX, commandX, 0x0X) \
I have both the uppercase and lowercase names in the table, because the upper case will be used for enums and the lowercase for function names.
Then I also define structs for each command to define what each command looks like:
typedef struct {...}command1_cmd_t;
typedef struct {...}command2_cmd_t;
etc.
Likewise I define structs for each command response:
typedef struct {...}command1_resp_t;
typedef struct {...}command2_resp_t;
etc.
Then I can define my command code enumeration:
enum
{
#define ENTRY(a,b,c) a##_CMD = c,
COMMAND_TABLE
#undef ENTRY
};
I can define my command length enumeration:
enum
{
#define ENTRY(a,b,c) a##_CMD_LENGTH = sizeof(b##_cmd_t);
COMMAND_TABLE
#undef ENTRY
};
I can define my response length enumeration:
enum
{
#define ENTRY(a,b,c) a##_RESP_LENGTH = sizeof(b##_resp_t);
COMMAND_TABLE
#undef ENTRY
};
I can determine how many commands there are as follows:
typedef struct
{
#define ENTRY(a,b,c) uint8_t b;
COMMAND_TABLE
#undef ENTRY
} offset_struct_t;
#define NUMBER_OF_COMMANDS sizeof(offset_struct_t)
NOTE: I never actually instantiate the offset_struct_t, I just use it as a way for the compiler to generate for me my number of commands definition.
Note then I can generate my table of function pointers as follows:
p_func_t jump_table[NUMBER_OF_COMMANDS] =
{
#define ENTRY(a,b,c) process_##b,
COMMAND_TABLE
#undef ENTRY
}
And my function prototypes:
#define ENTRY(a,b,c) void process_##b(void);
COMMAND_TABLE
#undef ENTRY
Now lastly for the coolest use ever, I can have the compiler calculate how big my transmit buffer should be.
/* reminder the sizeof a union is the size of its largest member */
typedef union
{
#define ENTRY(a,b,c) uint8_t b##_buf[sizeof(b##_cmd_t)];
COMMAND_TABLE
#undef ENTRY
}tx_buf_t
Again this union is like my offset struct, it is not instantiated, instead I can use the sizeof operator to declare my transmit buffer size.
uint8_t tx_buf[sizeof(tx_buf_t)];
Now my transmit buffer tx_buf is the optimal size and as I add commands to this comms handler, my buffer will always be the optimal size. Cool!
One other use is to create offset tables:
Since memory is often a constraint on embedded systems, I don't want to use 512 bytes for my jump table (2 bytes per pointer X 256 possible commands) when it is a sparse array. Instead I will have a table of 8bit offsets for each possible command. This offset is then used to index into my actual jump table which now only needs to be NUM_COMMANDS * sizeof(pointer). In my case with 10 commands defined. My jump table is 20bytes long and I have an offset table that is 256 bytes long, which is a total of 276bytes instead of 512bytes. I then call my functions like so:
jump_table[offset_table[command]]();
instead of
jump_table[command]();
I can create an offset table like so:
/* initialize every offset to 0 */
static uint8_t offset_table[256] = {0};
/* for each valid command, initialize the corresponding offset */
#define ENTRY(a,b,c) offset_table[c] = offsetof(offset_struct_t, b);
COMMAND_TABLE
#undef ENTRY
where offsetof is a standard library macro defined in "stddef.h"
As a side benefit, there is a very easy way to determine if a command code is supported or not:
bool command_is_valid(uint8_t command)
{
/* return false if not valid, or true (non 0) if valid */
return offset_table[command];
}
This is also why in my COMMAND_TABLE I reserved command byte 0. I can create one function called "process_reserved()" which will be called if any invalid command byte is used to index into my offset table.
X-Macros are essentially parameterized templates. So they are the right tool for the job if you need several similar things in several guises. They allow you to create an abstract form and instantiate it according to different rules.
I use X-macros to output enum values as strings. And since encountering it, I strongly prefer this form which takes a "user" macro to apply to each element. Multiple file inclusion is just far more painful to work with.
/* x-macro constructors for error and type
enums and string tables */
#define AS_BARE(a) a ,
#define AS_STR(a) #a ,
#define ERRORS(_) \
_(noerror) \
_(dictfull) _(dictstackoverflow) _(dictstackunderflow) \
_(execstackoverflow) _(execstackunderflow) _(limitcheck) \
_(VMerror)
enum err { ERRORS(AS_BARE) };
char *errorname[] = { ERRORS(AS_STR) };
/* puts(errorname[(enum err)limitcheck]); */
I'm also using them for function dispatch based on object type. Again by hijacking the same macro I used to create the enum values.
#define TYPES(_) \
_(invalid) \
_(null) \
_(mark) \
_(integer) \
_(real) \
_(array) \
_(dict) \
_(save) \
_(name) \
_(string) \
/*enddef TYPES */
#define AS_TYPE(_) _ ## type ,
enum { TYPES(AS_TYPE) };
Using the macro guarantees that all my array indices will match the associated enum values, because they construct their various forms using the bare tokens from the macro definition (the TYPES macro).
typedef void evalfunc(context *ctx);
void evalquit(context *ctx) { ++ctx->quit; }
void evalpop(context *ctx) { (void)pop(ctx->lo, adrent(ctx->lo, OS)); }
void evalpush(context *ctx) {
push(ctx->lo, adrent(ctx->lo, OS),
pop(ctx->lo, adrent(ctx->lo, ES)));
}
evalfunc *evalinvalid = evalquit;
evalfunc *evalmark = evalpop;
evalfunc *evalnull = evalpop;
evalfunc *evalinteger = evalpush;
evalfunc *evalreal = evalpush;
evalfunc *evalsave = evalpush;
evalfunc *evaldict = evalpush;
evalfunc *evalstring = evalpush;
evalfunc *evalname = evalpush;
evalfunc *evaltype[stringtype/*last type in enum*/+1];
#define AS_EVALINIT(_) evaltype[_ ## type] = eval ## _ ;
void initevaltype(void) {
TYPES(AS_EVALINIT)
}
void eval(context *ctx) {
unsigned ades = adrent(ctx->lo, ES);
object t = top(ctx->lo, ades, 0);
if ( isx(t) ) /* if executable */
evaltype[type(t)](ctx); /* <--- the payoff is this line here! */
else
evalpush(ctx);
}
Using X-macros this way actually helps the compiler to give helpful error messages. I omitted the evalarray function from the above because it would distract from my point. But if you attempt to compile the above code (commenting-out the other function calls, and providing a dummy typedef for context, of course), the compiler would complain about a missing function. For each new type I add, I am reminded to add a handler when I recompile this module. So the X-macro helps to guarantee that parallel structures remain intact even as the project grows.
Edit:
This answer has raised my reputation 50%. So here's a little more. The following is a negative example, answering the question: when not to use X-Macros?
This example shows the packing of arbitrary code fragments into the X-"record". I eventually abandoned this branch of the project and did not use this strategy in later designs (and not for want of trying). It became unweildy, somehow. Indeed the macro is named X6 because at one point there were 6 arguments, but I got tired of changing the macro name.
/* Object types */
/* "'X'" macros for Object type definitions, declarations and initializers */
// a b c d
// enum, string, union member, printf d
#define OBJECT_TYPES \
X6( nulltype, "null", int dummy , ("<null>")) \
X6( marktype, "mark", int dummy2 , ("<mark>")) \
X6( integertype, "integer", int i, ("%d",o.i)) \
X6( booleantype, "boolean", bool b, (o.b?"true":"false")) \
X6( realtype, "real", float f, ("%f",o.f)) \
X6( nametype, "name", int n, ("%s%s", \
(o.flags & Fxflag)?"":"/", names[o.n])) \
X6( stringtype, "string", char *s, ("%s",o.s)) \
X6( filetype, "file", FILE *file, ("<file %p>",(void *)o.file)) \
X6( arraytype, "array", Object *a, ("<array %u>",o.length)) \
X6( dicttype, "dict", struct s_pair *d, ("<dict %u>",o.length)) \
X6(operatortype, "operator", void (*o)(), ("<op>")) \
#define X6(a, b, c, d) #a,
char *typestring[] = { OBJECT_TYPES };
#undef X6
// the Object type
//forward reference so s_object can contain s_objects
typedef struct s_object Object;
// the s_object structure:
// a bit convoluted, but it boils down to four members:
// type, flags, length, and payload (union of type-specific data)
// the first named union member is integer, so a simple literal object
// can be created on the fly:
// Object o = {integertype,0,0,4028}; //create an int object, value: 4028
// Object nl = {nulltype,0,0,0};
struct s_object {
#define X6(a, b, c, d) a,
enum e_type { OBJECT_TYPES } type;
#undef X6
unsigned int flags;
#define Fread 1
#define Fwrite 2
#define Fexec 4
#define Fxflag 8
size_t length; //for lint, was: unsigned int
#define X6(a, b, c, d) c;
union { OBJECT_TYPES };
#undef X6
};
One big problem was the printf format strings. While it looks cool, it's just hocus pocus. Since it's only used in one function, overuse of the macro actually separated information that should be together; and it makes the function unreadable by itself. The obfuscation is doubly unfortunate in a debugging function like this one.
//print the object using the type's format specifier from the macro
//used by O_equal (ps: =) and O_equalequal (ps: ==)
void printobject(Object o) {
switch (o.type) {
#define X6(a, b, c, d) \
case a: printf d; break;
OBJECT_TYPES
#undef X6
}
}
So don't get carried away. Like I did.
Some real-world uses of X-Macros by popular and large projects:
Java HotSpot
In the Oracle HotSpot Virtual Machine for the Java® Programming Language, there is the file globals.hpp, which uses the RUNTIME_FLAGS in that way.
See the source code:
JDK 7
JDK 8
JDK 9
Chromium
The list of network errors in net_error_list.h is a long, long list of macro expansions of this form:
NET_ERROR(IO_PENDING, -1)
It is used by net_errors.h from the same directory:
enum Error {
OK = 0,
#define NET_ERROR(label, value) ERR_ ## label = value,
#include "net/base/net_error_list.h"
#undef NET_ERROR
};
The result of this preprocessor magic is:
enum Error {
OK = 0,
ERR_IO_PENDING = -1,
};
What I don't like about this particular use is that the name of the constant is created dynamically by adding the ERR_. In this example, NET_ERROR(IO_PENDING, -100) defines the constant ERR_IO_PENDING.
Using a simple text search for ERR_IO_PENDING, it is not possible to see where this constant it defined. Instead, to find the definition, one has to search for IO_PENDING. This makes the code hard to navigate and therefore adds to the obfuscation of the whole code base.
I like to use X macros for creating 'rich enumerations' which support iterating the enum values as well as getting the string representation for each enum value:
#define MOUSE_BUTTONS \
X(LeftButton, 1) \
X(MiddleButton, 2) \
X(RightButton, 4)
struct MouseButton {
enum Value {
None = 0
#define X(name, value) ,name = value
MOUSE_BUTTONS
#undef X
};
static const int *values() {
static const int a[] = {
None,
#define X(name, value) name,
MOUSE_BUTTONS
#undef X
-1
};
return a;
}
static const char *valueAsString( Value v ) {
#define X(name, value) static const char str_##name[] = #name;
MOUSE_BUTTONS
#undef X
switch ( v ) {
case None: return "None";
#define X(name, value) case name: return str_##name;
MOUSE_BUTTONS
#undef X
}
return 0;
}
};
This not only defines a MouseButton::Value enum, it also lets me do things like
// Print names of all supported mouse buttons
for ( const int *mb = MouseButton::values(); *mb != -1; ++mb ) {
std::cout << MouseButton::valueAsString( (MouseButton::Value)*mb ) << "\n";
}
I use a pretty massive X-macro to load contents of INI-file into a configuration struct, amongst other things revolving around that struct.
This is what my "configuration.def" -file looks like:
#define NMB_DUMMY(...) X(__VA_ARGS__)
#define NMB_INT_DEFS \
TEXT("long int") , long , , , GetLongValue , _ttol , NMB_SECT , SetLongValue ,
#define NMB_STR_DEFS NMB_STR_DEFS__(TEXT("string"))
#define NMB_PATH_DEFS NMB_STR_DEFS__(TEXT("path"))
#define NMB_STR_DEFS__(ATYPE) \
ATYPE , basic_string<TCHAR>* , new basic_string<TCHAR>\
, delete , GetValue , , NMB_SECT , SetValue , *
/* X-macro starts here */
#define NMB_SECT "server"
NMB_DUMMY(ip,TEXT("Slave IP."),TEXT("10.11.180.102"),NMB_STR_DEFS)
NMB_DUMMY(port,TEXT("Slave portti."),TEXT("502"),NMB_STR_DEFS)
NMB_DUMMY(slaveid,TEXT("Slave protocol ID."),0xff,NMB_INT_DEFS)
.
. /* And so on for about 40 items. */
It's a bit confusing, I admit. It quickly become clear that I don't actually want to write all those type declarations after every field-macro. (Don't worry, there's a big comment to explain everything which I omitted for brevity.)
And this is how I declare the configuration struct:
typedef struct {
#define X(ID,DESC,DEFVAL,ATYPE,TYPE,...) TYPE ID;
#include "configuration.def"
#undef X
basic_string<TCHAR>* ini_path; //Where all the other stuff gets read.
long verbosity; //Used only by console writing functions.
} Config;
Then, in the code, firstly the default values are read into the configuration struct:
#define X(ID,DESC,DEFVAL,ATYPE,TYPE,CONSTRUCTOR,DESTRUCTOR,GETTER,STRCONV,SECT,SETTER,...) \
conf->ID = CONSTRUCTOR(DEFVAL);
#include "configuration.def"
#undef X
Then, the INI is read into the configuration struct as follows, using library SimpleIni:
#define X(ID,DESC,DEFVAL,ATYPE,TYPE,CONSTRUCTOR,DESTRUCTOR,GETTER,STRCONV,SECT,SETTER,DEREF...)\
DESTRUCTOR (conf->ID);\
conf->ID = CONSTRUCTOR( ini.GETTER(TEXT(SECT),TEXT(#ID),DEFVAL,FALSE) );\
LOG3A(<< left << setw(13) << TEXT(#ID) << TEXT(": ") << left << setw(30)\
<< DEREF conf->ID << TEXT(" (") << DEFVAL << TEXT(").") );
#include "configuration.def"
#undef X
And overrides from commandline flags, that also are formatted with the same names (in GNU long form), are applies as follows in the foillowing manner using library SimpleOpt:
enum optflags {
#define X(ID,...) ID,
#include "configuration.def"
#undef X
};
CSimpleOpt::SOption sopt[] = {
#define X(ID,DESC,DEFVAL,ATYPE,TYPE,...) {ID,TEXT("--") #ID TEXT("="), SO_REQ_CMB},
#include "configuration.def"
#undef X
SO_END_OF_OPTIONS
};
CSimpleOpt ops(argc,argv,sopt,SO_O_NOERR);
while(ops.Next()){
switch(ops.OptionId()){
#define X(ID,DESC,DEFVAL,ATYPE,TYPE,CONSTRUCTOR,DESTRUCTOR,GETTER,STRCONV,SECT,...) \
case ID:\
DESTRUCTOR (conf->ID);\
conf->ID = STRCONV( CONSTRUCTOR ( ops.OptionArg() ) );\
LOG3A(<< TEXT("Omitted ")<<left<<setw(13)<<TEXT(#ID)<<TEXT(" : ")<<conf->ID<<TEXT(" ."));\
break;
#include "configuration.def"
#undef X
}
}
And so on, I also use the same macro to print the --help -flag output and sample default ini file, configuration.def is included 8 times in my program. "Square peg into a round hole", maybe; how would an actually competent programmer proceed with this? Lots and lots of loops and string processing?
https://github.com/whunmr/DataEx
I am using the following xmacros to generate a C++ class, with serialize and deserialize functionality built in.
#define __FIELDS_OF_DataWithNested(_) \
_(1, a, int ) \
_(2, x, DataX) \
_(3, b, int ) \
_(4, c, char ) \
_(5, d, __array(char, 3)) \
_(6, e, string) \
_(7, f, bool)
DEF_DATA(DataWithNested);
Usage:
TEST_F(t, DataWithNested_should_able_to_encode_struct_with_nested_struct) {
DataWithNested xn;
xn.a = 0xCAFEBABE;
xn.x.a = 0x12345678;
xn.x.b = 0x11223344;
xn.b = 0xDEADBEEF;
xn.c = 0x45;
memcpy(&xn.d, "XYZ", strlen("XYZ"));
char buf_with_zero[] = {0x11, 0x22, 0x00, 0x00, 0x33};
xn.e = string(buf_with_zero, sizeof(buf_with_zero));
xn.f = true;
__encode(DataWithNested, xn, buf_);
char expected[] = { 0x01, 0x04, 0x00, 0xBE, 0xBA, 0xFE, 0xCA,
0x02, 0x0E, 0x00 /*T and L of nested X*/,
0x01, 0x04, 0x00, 0x78, 0x56, 0x34, 0x12,
0x02, 0x04, 0x00, 0x44, 0x33, 0x22, 0x11,
0x03, 0x04, 0x00, 0xEF, 0xBE, 0xAD, 0xDE,
0x04, 0x01, 0x00, 0x45,
0x05, 0x03, 0x00, 'X', 'Y', 'Z',
0x06, 0x05, 0x00, 0x11, 0x22, 0x00, 0x00, 0x33,
0x07, 0x01, 0x00, 0x01};
EXPECT_TRUE(ArraysMatch(expected, buf_));
}
Also, another example is in https://github.com/whunmr/msgrpc.
Chromium has an interesting variation of a X-macro at dom_code_data.inc. Except it's not just a macro, but an entirely separate file.
This file is intended for keyboard input mapping between different platforms' scancodes, USB HID codes, and string-like names.
The file contains code like:
DOM_CODE_DECLARATION {
// USB evdev XKB Win Mac Code
DOM_CODE(0x000000, 0x0000, 0x0000, 0x0000, 0xffff, NULL, NONE), // Invalid
...
};
Each macro invocation actually passes in 7 arguments, and the macro can choose which arguments to use and which to ignore. One usage is to map between OS keycodes and platform-independent scancodes and DOM strings. Different macros are used on different OSes to pick the keycodes appropriate for that OS.
// Table of USB codes (equivalent to DomCode values), native scan codes,
// and DOM Level 3 |code| strings.
#if defined(OS_WIN)
#define DOM_CODE(usb, evdev, xkb, win, mac, code, id) \
{ usb, win, code }
#elif defined(OS_LINUX)
#define DOM_CODE(usb, evdev, xkb, win, mac, code, id) \
{ usb, xkb, code }
#elif defined(OS_MACOSX)
#define DOM_CODE(usb, evdev, xkb, win, mac, code, id) \
{ usb, mac, code }
#elif defined(OS_ANDROID)
#define DOM_CODE(usb, evdev, xkb, win, mac, code, id) \
{ usb, evdev, code }
#else
#define DOM_CODE(usb, evdev, xkb, win, mac, code, id) \
{ usb, 0, code }
#endif
#define DOM_CODE_DECLARATION const KeycodeMapEntry usb_keycode_map[] =
#include "ui/events/keycodes/dom/dom_code_data.inc"
#undef DOM_CODE
#undef DOM_CODE_DECLARATION
My humble example:
One of the steps to speed up the FFmpeg HEVC decoder - hardcode a matrix consisting of only three rows of small integer coefficients, which is used in several places:
https://github.com/aliakseis/FFmpegPlayer/commit/53a28b61cd98e1dda6d04251b713d39122c021d2#diff-8c65aa37510be2621e7b5a550a33c445b4c85607a789c9b483c2e78cdffcd65bL607
Related
I am posting this question here after I have done enough research within our community. However, I couldn't find a proper solution for my problem yet. So, I am posting my question here.
#define EXPAND_AS_ENUMERATION(a) CODE_##a,
#define EXPAND_AS_ARRAY(a) a,
#define CODE_TABLE(EXPAND)\
EXPAND(0x00E30054uL)\
EXPAND(0x00ED3581uL)\
EXPAND(0x00ED3983uL)\
EXPAND(0x00EE0368uL)\
EXPAND(0x00EE0368uL)\
EXPAND(0x00D01087uL)\
EXPAND(0x00ED4181uL)\
EXPAND(0x00505602uL)\
// Actual Event IDs which need to be selected at run time
#define SWC_FAULT_CODE_0x00E30054_EVENT 113
#define SWC_FAULT_CODE_0x00ED3581_EVENT 213
#define SWC_FAULT_CODE_0x00ED3983_EVENT 432
#define SWC_FAULT_CODE_0x00EE0368_EVENT 411
#define SWC_FAULT_CODE_0x00EE0368_EVENT 311
#define SWC_FAULT_CODE_0x00D01087_EVENT 231
#define SWC_FAULT_CODE_0x00ED4181_EVENT 471
#define SWC_FAULT_CODE_0x00505602_EVENT 419
#define prefix_str SWC_FAULT_CODE
#define postfix_str _EVENT
#define Get_EventID_FROM_CODE(code) ????? // ex: when code= 0x00ED3581, then it should return SWC_FAULT_CODE_0x00ED3581_EVENT macro or it's value 213
#define Get_EventID_FROM_ENUM(code_enum) ????? // ex: when code_enum= CODE_0x00ED3581, then it should return SWC_FAULT_CODE_0x00ED3581_EVENT macro or it's value 213
#define Get_CodeEnumName(code) ????? // ex: when code = 0x00ED3581, then it should return DTC_0x00ED3581 which is enum element
typedef enum
{
CODE_TABLE(EXPAND_AS_ENUMERATION)
CODE_COUNT
}codeList_t ;
void Cycle_1ms(const uint32 code)
{
// Based on code value, I want to get the macro value of SWC_FAULT_CODE_0xZZZZZZZZ_EVENT.
// ex: when code = 0x00ED3581, then eventID = SWC_FAULT_CODE_0x00ED3581_EVENT = 213
uint16 eventID_FromCode = Get_EventID(code);
}
void Cycle_1ms_anotherFunc(codeList_t code_enum)
{
// Based on code value, I want to get the macro value of SWC_FAULT_CODE_0xZZZZZZZZ_EVENT.
// ex: when code = 0x00ED3581, then eventID = SWC_FAULT_CODE_0x00ED3581_EVENT = 213
uint16 eventID_FromCodeEnum = Get_EventID_FROM_ENUM(code_enum);
}
void callback_func(uint32 code, uint8* buf)
{
// here, based on code value Get_CodeEnumName() should provide the enum element for that code. ex: when code= 0x00ED3581, enum_var = DTC_0x00ED3581
codeList_t enum_var = Get_CodeEnumName(code);
}
Here, CODE_TABLE will be changed from project to project and number of elements with in this table. After reading several articles and topics on Xmacros, I though of using Xmacros concept here to avoid looping and heavy use of RAM memory .
You cannot use X macros with run-time input, they are expanded at compile time. So if you need to do table look-ups based on run-time values, they are not the solution.
You can however use X macros to generate a look-up table and then use a magic number compile-time constant to expand into an enum, which in turn is corresponding to a look-up table index:
#define GET_EVENT_ID(code) LOOKUP[CODE_##code]
The GET_EVENT_ID expands to something like LOOKUP[CODE_0x00ED3581] which is a an array access.
Also the "events" could be bunched together with the codes in the same X macro list even if you don't need to use them in every macro. Also note that you have duplicate items in your X macro list which won't work since you plan to use it for generating unique enum constants. We can change it like this:
#define CODE_TABLE(X) \
/* code event */ \
X(0x00E30054uL, 113) \
X(0x00ED3581uL, 213) \
X(0x00ED3983uL, 432) \
X(0x00EE0368uL, 411) \
X(0x00D01087uL, 231) \
X(0x00ED4181uL, 471) \
X(0x00505602uL, 419) \
Then create SWC_FAULTS as enum constants instead of #defines:
// create SWC_FAULT_CODE_0x00ED3581_EVENT constants:
#define SWC_FAULT(code,event) SWC_FAULT_CODE_##code##_EVENT = event,
enum
{
CODE_TABLE(SWC_FAULT)
};
And then the enum to use for index of the lookup table:
// create enums like CODE__0x00ED3581:
#define EXPAND_AS_ENUMERATION(code, event) CODE_##code,
typedef enum
{
CODE_TABLE(EXPAND_AS_ENUMERATION)
CODE_COUNT
}code_list_t ;
A complete example:
#include <inttypes.h>
#include <stdio.h>
#define CODE_TABLE(X) \
/* code event */ \
X(0x00E30054uL, 113) \
X(0x00ED3581uL, 213) \
X(0x00ED3983uL, 432) \
X(0x00EE0368uL, 411) \
X(0x00D01087uL, 231) \
X(0x00ED4181uL, 471) \
X(0x00505602uL, 419) \
// create SWC_FAULT_CODE_0x00ED3581_EVENT constants:
#define SWC_FAULT(code,event) SWC_FAULT_CODE_##code##_EVENT = event,
enum
{
CODE_TABLE(SWC_FAULT)
};
// create enums like CODE__0x00ED3581:
#define EXPAND_AS_ENUMERATION(code, event) CODE_##code,
typedef enum
{
CODE_TABLE(EXPAND_AS_ENUMERATION)
CODE_COUNT
}code_list_t ;
// create look-up table containing SWC_FAULT_CODE_0x00ED3581_EVENT
// use designated initializers to get [CODE__0x00ED3581] = SWC_FAULT_CODE_0x00ED3581_EVENT
#define LOOKUP_TABLE(code,event) [CODE_##code] = SWC_FAULT_CODE_##code##_EVENT,
static const uint32_t LOOKUP[CODE_COUNT] =
{
CODE_TABLE(LOOKUP_TABLE)
};
_Static_assert(sizeof LOOKUP/sizeof *LOOKUP == CODE_COUNT, "LOOKUP table corrupt");
#define GET_EVENT_ID(code) LOOKUP[CODE_##code]
int main()
{
printf("0x%.8" PRIX32 " = %"PRIu32 "\n", 0x00ED3581uL, GET_EVENT_ID(0x00ED3581uL));
return 0;
}
Output: 0x00ED3581 = 213.
On gcc x86 the whole table can get optimized out leaving just this:
mov edx, 213
mov esi, 15545729
xor eax, eax
mov edi, OFFSET FLAT:.LC0
You could expand Get_EventID_FROM_CODE as a very long chain of ternary operators (?:). XMacro could be expanded inside the other macro doing the trick.
This would let you avoid using functions. Moreover, the solution accepts any format of integer literal and variables as well. It expands to a true C constant if possible. The only disadvantage is evaluation of the argument expressions but it is a common issue for macros.
#include <inttypes.h>
#include <stdio.h>
#define CODE_TABLE(X, ...) \
X(0x00E30054uL, 113, __VA_ARGS__) \
X(0x00ED3581uL, 213, __VA_ARGS__) \
X(0x00ED3983uL, 432, __VA_ARGS__) \
X(0x00EE0368uL, 411, __VA_ARGS__) \
X(0x00D01087uL, 231, __VA_ARGS__) \
X(0x00ED4181uL, 471, __VA_ARGS__) \
X(0x00505602uL, 419, __VA_ARGS__) \
// expands to -1 for invalid code
#define GET_EVENT_ID_(CODE,ENUM,VAR) (VAR) == (CODE) ? ENUM :
#define GET_EVENT_ID(code_var) (CODE_TABLE(GET_EVENT_ID_, code_var) -1)
int main()
{
#define DBG(CODE) \
printf("%s 0x%08lx = %d\n", #CODE, (unsigned long)(CODE), GET_EVENT_ID(CODE))
DBG(0x00ED3983uL);
DBG(0x00ED3983);
DBG(0xED3983);
int32_t x = 0x00D01087uL;
DBG(x);
// expand to a true constant if possible
struct X { char x[GET_EVENT_ID(0xED3983)]; };
printf("%zi\n", sizeof(struct X));
return 0;
}
Produces an expected output of:
0x00ED3983uL 0x00ed3983 = 432
0x00ED3983 0x00ed3983 = 432
0xED3983 0x00ed3983 = 432
x 0x00d01087 = 231
432
I'm looking for a way to cleanly define an array of strings in PROGMEM for an AVR project. I have a command line processor that needs a list of command strings.
The traditional way to do it on the AVR architecture is to define each string separately, then an array of pointers to those strings. This is extremely verbose and ugly:
typedef struct
{
PGM_P str; // pointer to command string
uint8_t str_len; // length of command string
uint8_t id; // CLI_COM_* ID number
} CLI_COMMAND_t;
const char CLI_STR_TEMP[] PROGMEM = "TEMP";
const char CLI_STR_POWER[] PROGMEM = "POWER";
...
const CLI_COMMAND_t cli_cmd_table[] = { { CLI_STR_TEMP, sizeof(CLI_STR_TEMP), CLI_COM_TEMP },
{ CLI_STR_POWER, sizeof(CLI_STR_POWER), CLI_COM_POWER },
...
};
(CLI_COM_* are enum'ed indicies, but could be replaced by function pointers or something)
This mess could be reduced using macros to define the strings and build the table, something like:
#define FLASH_STRING(NAME...) const char CLI_STR_ ## NAME [] PORGMEM = #NAME;
#define FSTR(NAME...) { CLI_STR_ ## NAME, sizeof(CLI_STR_ ## NAME), CLI_COM_ ## NAME) }
FLASH_STRING(TEMP);
FLASH_STRING(POWER);
CLI_COMMAND_t cli_cmd_table[] = { FSTR(TEMP), FSTR(POWER) };
(untested, btw, but should be fine)
However, I would like to define all my strings only once and have a macro generate both the individual strings and the array of pointers/sizes/enum references.
On the Arduino platform there is a FLASH_STRING_ARRAY macro which I can't quite figure out, but which doesn't seem to compile either. You can see it here: http://pastebin.com/pMiV5CMr Maybe it's C++ only or something. Also it seems like it can only be used inside a function, not globally.
String tables on AVR have long been a pain and inelegant. Short of writing a little program to generate the necessary code it would be nice to have a way to define it with macros.
Bonus points: Generate the CLI_COM_* constants with the same macro, either as an enum or with #defines.
EDIT: I suppose another name for this would be iterative declaration via a macro.
SOLUTION: Thanks to luser, I came up with this solution:
typedef struct
{
PGM_P str; // pointer to command string
uint8_t str_len; // length of command string
uint8_t id; // CLI_COM_* ID number
} CLI_COMMAND_LUT_t;
#define COMMAND_TABLE \
ENTRY(testA) \
ENTRY(testB) \
ENTRY(testC)
enum {
#define ENTRY(a) CLI_COM_ ## a,
COMMAND_TABLE
#undef ENTRY
};
#define ENTRY(a) const char CLI_STR_ ## a PROGMEM = #a;
COMMAND_TABLE
#undef ENTRY
CLI_COMMAND_LUT_t command_lut[] PROGMEM = {
#define ENTRY(a) {CLI_STR_ ## a, sizeof(CLI_STR_ ## a), CLI_COM_ ## a},
COMMAND_TABLE
#undef ENTRY
};
The produces the following output from the preprocessor:
typedef struct
{
PGM_P str;
uint8_t str_len;
uint8_t id;
} CLI_COMMAND_LUT_t;
enum {
CLI_COM_testA, CLI_COM_testB, CLI_COM_testC,
};
const char CLI_STR_testA PROGMEM = "testA"; const char CLI_STR_testB PROGMEM = "testB"; const char CLI_STR_testC PROGMEM = "testC";
CLI_COMMAND_LUT_t command_lut[] PROGMEM = {
{CLI_STR_testA, sizeof(CLI_STR_testA), CLI_COM_testA}, {CLI_STR_testB, sizeof(CLI_STR_testB), CLI_COM_testB}, {CLI_STR_testC, sizeof(CLI_STR_testC), CLI_COM_testC},
};
So all that lot can be wrapped up an a region and I end up with just a simple and most importantly single definition of each command that serves as both its string name and the reference for the code.
Thanks a lot guys, much appreciated!
X-Macros might help.
strings.x:
X(TEMP, "Temp")
X(POWER, "Power")
Usage:
// String concatenation macros
#define CONCAT(a, b) CONCAT2(a, b)
#define CONCAT2(a, b) a ## b
// Generate string variables
#define X(a, b) const char CONCAT(CLI_STR_, a) [] PROGMEM = b;
#include "strings.x"
#undef X
// Generate enum constants
#define X(a, b) CONCAT(CLI_COM_, a),
enum {
#include "strings.x"
};
#undef X
// Generate table
#define X(a, b) { CONCAT(CLI_STR_, a), sizeof(CONCAT(CLI_STR_, a)), CONCAT(CLI_COM_, a) },
const CLI_COMMAND_t cli_cmd_table[] = {
#include "strings.x"
};
#undef X
This is untested.
I use C bitfields to store data in memory. For archive usage these data has to be written to a file (and later on be combined with data from another machine). It seems to be a bad idea to save the bitfields directly to the file, since the arrangement of data is implementation specific.
For this reason I wrote some methods to "serialize" these bitfields to save them in a unified format:
/* uint16 is a unsigned int with size 16 */
typedef struct {
uint16 a : 1;
/* ... just examples ... */
uint16 z : 13;
} data;
void save_data(FILE* fp, data d) {
uint16 tmp;
tmp = d.a;
fwrite(&tmp,sizeof(uint16),1,fp);
/* ... */
tmp = d.z;
fwrite(&tmp,sizeof(uint16),1,fp);
}
While this is perfectly working, it seems not to be well to extend, since adding more members in data requires adding the data to the save routine as well.
Is there any trick to automatically convert bitfield data to a unified format without needing to adapt the routine/macro when changing the bitfield data?
Here is one method. I cannot recommend it, but it's out there and it sort of works, so why not look at it. This incarnation is still platform-dependent but you can easily switch to a platform-independent, possibly human-readable format. Error handling is omitted for brevity.
// uglymacro.h
#if defined(DEFINE_STRUCT)
#define BEGINSTRUCT(struct_tag) typedef struct struct_tag {
#define ENDSTRUCT(struct_typedef) } struct_typedef;
#define BITFIELD(name,type,bit) type name : bit;
#define FIELD(name,type) type name;
#define ARRAYFIELD(name,type,size) type name[size];
#elif defined(DEFINE_SAVE)
#define BEGINSTRUCT(struct_tag) void save_##struct_tag(FILE* fp, \
struct struct_tag* p_a) {
#define ENDSTRUCT(struct_typedef) }
#define BITFIELD(name,type,bit) { type tmp; tmp = p_a->name; \
fwrite (&tmp, sizeof(type), 1, fp); }
#define FIELD(name,type) { fwrite (&p_a->name, sizeof(p_a->name), 1, fp); }
#define ARRAYFIELD(name,type,size) { fwrite (p_a->name, sizeof(p_a->name[0]), size, fp); }
#elif defined(DEFINE_READ)
#define BEGINSTRUCT(struct_tag) void read_##struct_tag(FILE* fp, \
struct struct_tag* p_a) {
#define ENDSTRUCT(struct_typedef) }
#define BITFIELD(name,type,bit) { type tmp; fread (&tmp, sizeof(type), 1, fp); \
p_a->name = tmp; }
#define FIELD(name,type) { fread (&p_a->name, sizeof(p_a->name), 1, fp); }
#define ARRAYFIELD(name,type,size) { fread (p_a->name, sizeof(p_a->name[0]), size, fp); }
#else
#error "Must define either DEFINE_STRUCT or DEFINE_SAVE or DEFINE_READ"
#endif
#undef DEFINE_STRUCT
#undef DEFINE_READ
#undef DEFINE_WRITE
#undef BEGINSTRUCT
#undef ENDSTRUCT
#undef FIELD
#undef BITFIELD
#undef ARRAYFIELD
Your struct definition looks like this:
// mystruct_def.h
BEGINSTRUCT(mystruct)
BITFIELD(a,int,1)
FIELD(b,int)
ARRAYFIELD(c,int,10)
ENDSTRUCT(mystruct)
You use it like this:
// in mystruct.h file
#define DEFINE_STRUCT
#include "uglymacro.h"
#include "mystruct_def.h"
// in mystruct.c file
#include "mystruct.h"
#define DEFINE_READ
#include "mystruct_def.h"
#define DEFINE_WRITE
#include "mystruct_def.h"
Frankly, by modern standards this method is ugly. I have used something similar about 20 years ago and it was ugly back then.
Another alternative is using a more humane code-generation facility instead of the C preprocessor.
If you are willing to invest a bit you can use tools like P99 for "statement unrolling":
// in header
#define MY_BITFIELDS a, z
#define WRITE_IT(X) fwrite(&(unsigned){ d.X }, sizeof(unsigned), 1, fp)
#define WRITE_ALL(...) P99_SEP(WRITE_IT, __VA_ARGS__)
// in your function
WRITE_ALL(MY_BITFIELDS);
BTW, never use int for bitfields if you can avoid this. The semantic of a set of bits is much better matched by unsigned.
With a bit of more macro coding you could even use something like
#define MY_BITFIELDS (a, 1), (z, 11)
to produce the struct declaration and the write part.
Why not use a human readable text format?
typedef struct {
int a : 1;
/* ... just examples ... */
int z : 13;
} data;
void save_data(FILE* fp, data d) {
fprintf( fp, "a:%d\n", d.a );
fprintf( fp, "b:%d\n", d.b );
...
fprintf( fp, "z:%d\n", d.z );
}
The advantage of this technique is that somebody using any different language could quickly write a parser to load your data on any machine, any architecture.
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.