program What is a good reference documenting patterns of use of X-Macros in C(or possibly C++)?



types of macros in c (10)

A basic definition and example and a few references for "X-Macros" is given in this wikipedia entry on the C pre-processor:

An X-Macro is a header file (commonly using a ".def" extension instead of the traditional ".h") that contains a list of similar macro calls (which can be referred to as "component macros").

What are some good sources of information on how to use this powerful technique? Are there well-known open source libraries using this method?


Answer #1

Overloading operator<< for a private enum

This isn't possible. You want to accept an argument of type supportedMessageTypes, so it must be visible. There's no way around it.

Also, a friend function wouldn't be bad here; this is one of the intented scenarios for friendship.


Answer #2

I use X Macros() in code a lot. The value comes from only adding new data only to the "X list" and not modifying any other code.

The most common use of X Macros() is for associating error text with error codes. When new error codes are added, programmers must remember to add the code and the text, typically in separate places. The X Macro allows the new error data to be added in a single place and get automatically populated anywhere it is needed.

Unfortunately, the mechanisms use a lot of pre-compiler magic that can make the code somewhat hard to read (e.g. string joining with token1##token2, string creation with #token). Because of this I typically explain what the X Macro is doing in the comments.

Here is an example using the error/return values. All new data gets added to the "X_ERROR" list. None of the other code hast to be modified.

/* 
 * X Macro() data list
 * Format: Enum, Value, Text
 */
#define X_ERROR \
  X(ERROR_NONE,   1, "Success") \
  X(ERROR_SYNTAX, 5, "Invalid syntax") \
  X(ERROR_RANGE,  8, "Out of range")

/* 
 * Build an array of error return values
 *   e.g. {0,5,8}
 */
static int ErrorVal[] =
{
  #define X(Enum,Val,Text)     Val,
   X_ERROR
  #undef X
};

/* 
 * Build an array of error enum names
 *   e.g. {"ERROR_NONE","ERROR_SYNTAX","ERROR_RANGE"}
 */

static char * ErrorEnum[] = {
  #define X(Enum,Val,Text)     #Enum,
   X_ERROR
  #undef X
};

/* 
 * Build an array of error strings
 *   e.g. {"Success","Invalid syntax","Out of range"}
 */
static char * ErrorText[] = {
  #define X(Enum,Val,Text)     Text,
   X_ERROR
  #undef X
};

/* 
 * Create an enumerated list of error indexes
 *   e.g. 0,1,2
 */
enum {
  #define X(Enum,Val,Text)     IDX_##Enum,
   X_ERROR
  #undef X
  IDX_MAX   /* Array size */
};

void showErrorInfo(void)
{
    int i;

    /* 
     * Access the values
     */
    for (i=0; i<IDX_MAX; i++)
        printf(" %s == %d [%s]\n", ErrorEnum[i], ErrorVal[i], ErrorText[i]);

}

You can also use X Macros() to generate code. For example to test if an error value is "known", the X Macro can generate cases in a switch statement:

 /*
  * Test validity of an error value
  *      case ERROR_SUCCESS:
  *      case ERROR_SYNTAX:
  *      case ERROR_RANGE:
  */

  switch(value)
  {

  #define X(Enum,Val,Text)     case Val:
   X_ERROR
  #undef X
         printf("Error %d is ok\n",value);
         break;
      default:
         printf("Invalid error: %d\n",value);
         break;
  }

Answer #3

I'm fond of using = {0}; to initialize structures without needing to call memset.

struct something X = {0};

This will initialize all of the members of the struct (or array) to zero (but not any padding bytes - use memset if you need to zero those as well).

But you should be aware there are some issues with this for large, dynamically allocated structures.


Answer #4

What is your favorite C programming trick?

C99 offers some really cool stuff using anonymous arrays:

Removing pointless variables

{
    int yes=1;
    setsockopt(yourSocket, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int));
}

becomes

setsockopt(yourSocket, SOL_SOCKET, SO_REUSEADDR, (int[]){1}, sizeof(int));

Passing a Variable Amount of Arguments

void func(type* values) {
    while(*values) {
        x = *values++;
        /* do whatever with x */
    }
}

func((type[]){val1,val2,val3,val4,0});

Static linked lists

int main() {
    struct llist { int a; struct llist* next;};
    #define cons(x,y) (struct llist[]){{x,y}}
    struct llist *list=cons(1, cons(2, cons(3, cons(4, NULL))));
    struct llist *p = list;
    while(p != 0) {
        printf("%d\n", p->a);
        p = p->next;
    }
}

Any I'm sure many other cool techniques I haven't thought of.


Answer #5

I cannot agree with some of the premises in your question. In particular, when you say that declaring the operator<< as a friend function breaks encapsulation. It breaks encapsulation in exactly the same way as any member function of your type breaks encapsulation. The operator<< is part of your type and has access to the private parts, but that is not a breakage of encapsulation. Note that in C++ not only member functions belong to the interface of the type. Google for interface principle.

class test {
   enum E { ok, nok };
   friend std::ostream& operator<<( std::ostream&, E );
};
std::ostream& operator<<( std::ostream& out, E e ) {
   if ( e == ok ) out << "ok";
   else out << "nok";
   return out;
}

Note that you are not opening your class to anyone, only to one of your functions. If you feel at unease, think of this almost equivalent way of generating the same code:

class test {
    enum E { ok, nok }
    friend std::ostream& operator<<( std::ostream& out, E e ) {
       if ( e == ok ) out << "ok";
       else out << "nok";
       return out;
    }
};

How is that code less encapsulated than your original code?


Answer #6

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 */
#def 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 {...}response1_resp_t;
typedef struct {...}response2_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 generator for me my number of commands.

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!


Answer #7

Dr. Dobb's has an article on this.


Answer #8

http://ideone.com/gMTZ6

Dispite my efforts, I couldn't find a way to do this without the friend keyword. On the other hand, this does not break encapsulation, as nobody outside of your class can use the function, since they cannot access the type being used in the type lookup. Ergo, you're still fully encapsulated.


Answer #9

Unusual usage of .h file in C

Preprocessor directives like #include are just doing some textual substitution (see the documentation of GNU cpp inside GCC). It can occur at any place (outside of comments and string literals).

However, a #include should have its # as the first non-blank character of its line. So you'll code

float h[N] = {
  #include "f1.h"
};

The original question did not have #include on its own line, so had wrong code.

It is not normal practice, but it is permitted practice. In that case, I would suggest using some other extension than .h e.g. use #include "f1.def" or #include "f1.data" ...

Ask your compiler to show you the preprocessed form. With GCC compile with gcc -C -E -Wall yoursource.c > yoursource.i and look with an editor or a pager into the generated yoursource.i

I actually prefer to have such data in its own source file. So I would instead suggest to generate a self-contained h-data.c file using e.g. some tool like GNU awk (so file h-data.c would start with const float h[345] = { and end with };...) And if it is a constant data, better declare it const float h[] (so it could sit in read-only segment like .rodata on Linux). Also, if the embedded data is big, the compiler might take time to (uselessly) optimize it (then you could compile your h-data.c quickly without optimizations).


Answer #10

While reading Quake 2 source code I came up with something like this:

double normals[][] = {
  #include "normals.txt"
};

(more or less, I don't have the code handy to check it now).

Since then, a new world of creative use of the preprocessor opened in front of my eyes. I no longer include just headers, but entire chunks of code now and then (it improves reusability a lot) :-p

Thanks John Carmack! xD





c-preprocessor