Andre
15 posts
GNU's online docs on the C Preprocessor are pretty thorough if you're interested in learning about the kinds of things that macros can do. Even if you only ever use MSVC, there's lots of good info there.
Simon Anciaux
1194 posts
Does anyone knows how Jonathan Blow's defer macro works ? Example of how he uses it at the end of this blog post.
 1 2 auto name = filenames[i]; defer { gamelib_free_string(name); }; 

I found those two pages that show how to make defer macros, but I'm interested to know how Jonathan's curly braces syntax works.
http://the-witness.net/news/2012/11/scopeexit-in-c11/
http://www.gingerbill.org/article/defer-in-cpp.html
TM
13 posts
mrmixer
Does anyone knows how Jonathan Blow's defer macro works ? Example of how he uses it at the end of this blog post.
 1 2 auto name = filenames[i]; defer { gamelib_free_string(name); }; 

I found those two pages that show how to make defer macros, but I'm interested to know how Jonathan's curly braces syntax works.
http://the-witness.net/news/2012/11/scopeexit-in-c11/
http://www.gingerbill.org/article/defer-in-cpp.html

You typically need a dummy struct and an operator overload to do this.
I think he is doing this:
 1 2 3 4 5 6 7 8 struct DEFER_TAG {}; template< class Func > ScopeExit< Func > operator+( DEFER_TAG, Func&& func ) { return MakeScopeExit< Func >( std::forward< Func >( func ) ); } #define defer auto STRING_JOIN2(scope_exit_, __LINE__) = DEFER_TAG() + [&]() 

This enables you to have curly brackets after the macro, which is actually the definition of a lambda function which is then used to construct a ScopeExit object, which executes it at the end of the scope.
Simon Anciaux
1194 posts
Edited by Simon Anciaux on Reason: Was missing a line
Thanks.
Here is the complete code:
  1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 #include template struct Defer { Defer( F f ) : f( f ) {} ~Defer( ) { f( ); } F f; }; template Defer makeDefer( F f ) { return Defer( f ); }; #define __defer( line ) defer_ ## line #define _defer( line ) __defer( line ) struct defer_dummy { }; template Defer operator+( defer_dummy, F&& f ) { return makeDefer( std::forward( f ) ); } #define defer auto _defer( __LINE__ ) = defer_dummy( ) + [ & ]( ) 
Andrew Bromage
183 posts / 1 project
Research engineer, resident maths nerd (Erdős number 3).
Edited by Andrew Bromage on
A variant on the X macro is the "header file of macro calls", which I learned from the Clang source code. I'm very much a convert to this style of boilerplate-scrapping, and it's saved my bacon a few times.

Here's an example from Homebrew OS. The interrupt table is kind of complex, because it has to deal with machine exceptions/traps, hardware interrupts, and software-defined interrupts. For some traps, the CPU pushes extra information onto the stack (e.g. page fault pushes information about the memory access onto the stack), so the stack frame may not be the same in all cases. Some traps need special care (e.g. non-maskable interrupts or the machine-check exception).

To handle all the complexity, I define the interrupt table a header file which contains a big block of macro calls, called interrupt_table.inc:

  1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 TRAP(0x00,__handle_de) TRAP_SPC(0x01,__handle_db) TRAP_IST2(0x02,__handle_nmi) USER_TRAP(0x03,__handle_np) USER_TRAP(0x04,__handle_of) USER_TRAP(0x05,__handle_br) TRAP(0x06,__handle_ud) TRAP(0x07,__handle_nm) TRAP_IST1(0x08,__handle_df) TRAP(0x09,__handle_fpu_of) TRAP_ERR(0x0a,__handle_ts) TRAP_IST1(0x0b,__handle_np) TRAP_IST1(0x0c,__handle_ss) TRAP_IST1(0x0d,__handle_gp) TRAP_SPC(0x0e,__handle_pf) TRAP(0x0f,__handle_trap_0f) TRAP(0x10,__handle_mp) TRAP_ERR(0x11,__handle_ac) TRAP_IST1(0x12,__handle_mc) // ...and so on for all 256 possible interrrupts... INTERRUPT(0xf8) INTERRUPT(0xf9) INTERRUPT(0xfa) TRAP(0xfb,__handle_ipi_slow) TRAP(0xfc,__handle_ipi_fast) TRAP(0xfd,__handle_apic_error) TRAP_SPC(0xfe,__handle_apic_spurious) TRAP(0xff,handle_ipi_reschedule) 

To use this, you do a bunch of #defines to say what all the cases mean, then #include the file.

So, for example, here is the code to set up the interrupt descriptor table (in C):

  1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 #define TRAP_IST1(n, f) \ extern void f(); \ idt_set_trap(n, f, 0, 1); #define TRAP_IST2(n, f) \ extern void f(); \ idt_set_trap(n, f, 0, 2); #define TRAP(n, f) \ extern void f(); \ idt_set_trap(n, f, 0, 3); #define TRAP_ERR TRAP #define USER_TRAP TRAP #define TRAP_SPC TRAP #define USER_TRAP_SPC TRAP #define INTERRUPT(n) \ extern void __irq_##n (); \ idt_set_int(n, __irq_##n, 0, 3); #include "interrupt_table.inc" 

And here is the code to automatically generate interrupt handler stubs (in assembler):

  1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 #define TRAP_ERR(n, f) \ ENTRY(f) ; \ INT_HANDLER_BODY(n, handle_trap) #define TRAP(n, f) \ ENTRY(f) ; \ pushq $0 ; \ INT_HANDLER_BODY(n, handle_trap) #define INTERRUPT(irqn) \ ENTRY(__irq_##irqn) ; \ pushq$0 ; \ INT_HANDLER_BODY(irqn, handle_interrupt) #define USER_TRAP TRAP // We don't want automatically-generated stubs for these cases. #define TRAP_SPC(n, f) #define TRAP_IST1(n, f) #define TRAP_IST2(n, f) #define USER_TRAP_SPC(n, f) #include "interrupt_table.inc" 

The reason why this approach work well is that there are 256 cases which need to be kept consistent between different source files, even written in different languages. The "header file of macro calls" keeps it all in one place.
34 posts
Edited by Shastic on

I feel embarrassed replying to this thread. Firstly, because some forums don't like people raising old threads. Also because this is so basic, all the experienced programmers know it. But I think it will help a C beginner, so here it is.

The X Macro is mentioned above. The tutorials I found on the internet in the past said, it is an old trick that few know about. Then they give examples that aren't very interesting, like auto generate an enum and strings for debugging.

I was reading an old AI book by Buckland where the text is easy to understand, except he really bought into object oriented, C++ templates, and UML diagrams. So I thought I'd use Casey's method of using a fat struct and a switch statement to translate his C++ code to C.

What I found while converting his state machine example, was code that needs to be close together so you can reason about it, is far apart when using a big switch statement in different functions. Then it occurred to me to use X Macros to auto generate the switch statements with function calls, so I can put related code close together in functions.

This is the list of items the X Macros need to do their thing:

  #define ENTITY_STATE_LIST \
X(ENTITY_STATE_NONE) \
X(ENTITY_STATE_ENTER_MINE_AND_DIG_FOR_NUGGET) \
X(ENTITY_STATE_VISIT_BANK_AND_DEPOSIT_GOLD) \
X(ENTITY_STATE_GO_HOME_AND_SLEEP_TIL_RESTED) \
X(ENTITY_STATE_QUENCH_THIRST) \
X(ENTITY_STATE_EAT_STEW) \
X(ENTITY_STATE_WIFES_GLOBAL) \
X(ENTITY_STATE_DO_HOUSE_WORK) \
X(ENTITY_STATE_VISIT_BATHROOM) \
X(ENTITY_STATE_COOK_STEW)


The first X Macro generates an enum, the second makes strings that match the enum.

enum entity_state {
#define X(name) name,
ENTITY_STATE_LIST
#undef X
ENTITY_STATES_MAX
};

static const char *entity_state_str[] = {
#define X(name) "name",
ENTITY_STATE_LIST
#undef X
"ENTITY_STATES_MAX"
};


Which generates these:

enum entity_state {
ENTITY_STATE_NONE,
ENTITY_STATE_ENTER_MINE_AND_DIG_FOR_NUGGET,
ENTITY_STATE_VISIT_BANK_AND_DEPOSIT_GOLD,
ENTITY_STATE_GO_HOME_AND_SLEEP_TIL_RESTED,
ENTITY_STATE_QUENCH_THIRST,
ENTITY_STATE_EAT_STEW,
ENTITY_STATE_WIFES_GLOBAL,
ENTITY_STATE_DO_HOUSE_WORK,
ENTITY_STATE_VISIT_BATHROOM,
ENTITY_STATE_COOK_STEW,
ENTITY_STATES_MAX
};

static const char *entity_state_str[] = {
"ENTITY_STATE_NONE",
"ENTITY_STATE_ENTER_MINE_AND_DIG_FOR_NUGGET",
"ENTITY_STATE_VISIT_BANK_AND_DEPOSIT_GOLD",
"ENTITY_STATE_GO_HOME_AND_SLEEP_TIL_RESTED",
"ENTITY_STATE_QUENCH_THIRST",
"ENTITY_STATE_EAT_STEW",
"ENTITY_STATE_WIFES_GLOBAL",
"ENTITY_STATE_DO_HOUSE_WORK",
"ENTITY_STATE_VISIT_BATHROOM",
"ENTITY_STATE_COOK_STEW",
"ENTITY_STATES_MAX"
};


Here are two X Macros that make switch statements that call functions related to the enum above:

        switch (state) {
#define X(name) case name: name##_enter(entity); break;
ENTITY_STATE_LIST
#undef X
case ENTITY_STATES_MAX:
break;
}

switch (state) {
#define X(name) case name: name##_execute(entity); break;
ENTITY_STATE_LIST
#undef X
case ENTITY_STATES_MAX:
break;
}


Which makes these:

switch (state) {
case ENTITY_STATE_NONE: ENTITY_STATE_NONE_enter(entity); break;
case ENTITY_STATE_ENTER_MINE_AND_DIG_FOR_NUGGET: ENTITY_STATE_ENTER_MINE_AND_DIG_FOR_NUGGET_enter(entity); break;
...
}

switch (state) {
case ENTITY_STATE_NONE: ENTITY_STATE_NONE_execute(entity); break;
case ENTITY_STATE_ENTER_MINE_AND_DIG_FOR_NUGGET: ENTITY_STATE_ENTER_MINE_AND_DIG_FOR_NUGGET_execute(entity); break;
...
}


Then in another file if you want, you write the functions the generated switch statements call.

internal void
ENTITY_STATE_NONE_enter(struct entity *entity)
{
}

internal void
ENTITY_STATE_NONE_execute(struct entity *entity)
{
}

internal void
ENTITY_STATE_ENTER_MINE_AND_DIG_FOR_NUGGET_enter(struct entity *entity)
{
}

internal void
ENTITY_STATE_ENTER_MINE_AND_DIG_FOR_NUGGET_execute(struct entity *entity)
{
}


When looking around this forum I found a blog by Cakelisp that mentioned them, then I found a link that actually has some good examples.

https://en.wikibooks.org/wiki/C_Programming/Preprocessor_directives_and_macros#X-Macros

So C has inheritance just as easy to read as C++, without using pointers. Well the X Macro part is ugly, but it is the same thing over and over.

34 posts

Mods, the above post is messed up. Is there a page here that gives instructions as to what tags to use to mark code?

Asaf Gartner
58 posts
Edited by Asaf Gartner on

We support markdown, so you can do the usual triple-backtick. For example:

c

#define ENTITY_STATE_LIST \
X(ENTITY_STATE_NONE) \
X(ENTITY_STATE_ENTER_MINE_AND_DIG_FOR_NUGGET) \
X(ENTITY_STATE_VISIT_BANK_AND_DEPOSIT_GOLD) \
X(ENTITY_STATE_GO_HOME_AND_SLEEP_TIL_RESTED) \
X(ENTITY_STATE_QUENCH_THIRST) \
X(ENTITY_STATE_EAT_STEW) \
X(ENTITY_STATE_WIFES_GLOBAL) \
X(ENTITY_STATE_DO_HOUSE_WORK) \
X(ENTITY_STATE_VISIT_BATHROOM) \
X(ENTITY_STATE_COOK_STEW)




34 posts