Register
handmade.network»Forums»Post your C/C++ macro tricks
Jack Mott
112 posts / 1 project

Web Developer by day, game hobbyist by night.

Post your C/C++ macro tricks
3 years, 4 months ago Edited by Jack Mott on June 7, 2016, 8:52 p.m. Reason: code
I learned of a neat macro trick today, maybe old hat to most of you but maybe not

"#" is a "stringify" operator, which you can use to sort of replicate reflection-ish features.

For instance say you wanted a utility function to serialize something to json, you can do something like this:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
#define writeInt(x) _writeInt(#x,x)

writeInt(mass);

//and it will expand to:

_writeInt("mass",mass);


#define loadInt(x,json) x = _loadInt(#x,json)

//expands to:

mass = _loadInt("mass",json);



Saves us a ton of boilerplate, and prevents you from miss typing string literals.

Dominik Madarász
14 posts / 1 project
I'm Dominik, a developer always loving to explore new ways of programming. ...
Post your C/C++ macro tricks
3 years, 4 months ago Edited by Dominik Madarász on June 8, 2016, 1:50 p.m. Reason: added macro.
Honestly I'm a big fan of macros, sometimes I even unnecessarily overuse them.

I either use it to add some reflection or I substitute common code snippets to make it easier for me when coding.

There is one particular macro I used to do, but then found out it's unpractical and also quite useless for me since I've left OOP for now:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
#define CLASS(p) class p\
{\
	inline virtual std::string _GetClassName_() { return #p; }

//which then could be used as
CLASS(TestClass)
    void DoStuff();
    //...
};

//due to missing brace in code, it broke some VS functionalities and highlighting (which breaks on everything now, excuse me for highlighting).
//I've got rid of this macro and added a factory (which is not related, see below), vector holding pair of string (class name) and class constructor.
//but tbh, I still use simplified version of CLASS macro for ex. as:
class BigDoor : Door
{
public:
    REGCLASS("BigDoor") // inline virtual std::string __GetClassName__() { return "BigDoor"; }
    //...
};
// and so on..


When it comes to macros, I do silly ones often, then there's common stuff like:
1
2
3
4
5
#define SCALL(x, c) if (x != nullptr) c

//or
#include <stdio.h>
#define ASSERT(p,q) if(!p) { fprintf(stderr, "ERROR: \"" ## q ## "\" IN " __FILE__ " AT LINE %d!\n", __LINE__); *(int*)0=0; } 


Which is pretty self-explanatory and maybe useless, I guess.

I'd like to see some interesting tricks, there's always a time to learn something new.
Jack Mott
112 posts / 1 project

Web Developer by day, game hobbyist by night.

Post your C/C++ macro tricks
3 years, 4 months ago
I like the SCALL! That could come in handy.

I just stumbled on another reflection-ish trick with enums, that I am really excited about because I spent hours trying to find a good way to get a ENUM tied to the strings it represents:

http://stackoverflow.com/question...convert-enum-names-to-string-in-c
Dominik Madarász
14 posts / 1 project
I'm Dominik, a developer always loving to explore new ways of programming. ...
Post your C/C++ macro tricks
3 years, 4 months ago
Thanks, I'll look into that one. It's nice to have this topic, always stuff to learn.
Mārtiņš Možeiko
1979 posts / 1 project
Post your C/C++ macro tricks
3 years, 4 months ago
I dislike macros that create multiple statements. Doing them for definitions or declarations is fine. But I'm strongly against mult-statement macros. Why? Because there is no easy way to debug them, meaning - you cannot step statement by statement and examing values in debugger.
6 posts
Post your C/C++ macro tricks
3 years, 4 months ago
Not too interesting, but funny:

1
#define private public
474 posts
Post your C/C++ macro tricks
3 years, 4 months ago
Horrowind
Not too interesting, but funny:

1
#define private public


That's not complete without

1
2
#define class struct
#define protected public
Daniel Rasmussen
7 posts
Post your C/C++ macro tricks
3 years, 4 months ago
Here's a little trick to creating generic functions and types. Multiple include with the same file, and you just switch the VAR_TYPE and VAR_NAME between includes.
This is a bounded/sized array implementation that only requires 3 lines of code to create a new type.
1
2
3
#define VAR_TYPE float // the type you want.
#define VAR_NAME f32 // type name appended to the struct / function.
#include "bound_array.cpp"



 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
// "main.cpp"
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <assert.h>

#define CONCAT_(a,b) a##b
#define CONCAT(a,b) CONCAT_(a,b)

#define VAR_TYPE float
#define VAR_NAME f32
#include "bound_array.cpp"

#define VAR_TYPE int64_t
#define VAR_NAME s64
#include "bound_array.cpp"

int main()
{
    Array_f32 eple = Array_f32_init(32);
    eple[31] = 91;
    printf("eple.size = %lu\neple[31] = %f\n", eple.size, eple[31]);
    
    
    Array_s64 pera = Array_s64_init(54);
    pera[24] = 3771;
    printf("pera.size = %lu\npera[24] = %li\n", pera.size, pera[24]);
    
    return 0;
}


 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
31
32
33
// "bound_array.cpp"
#ifndef VAR_TYPE
#error "VAR_TYPE is not defined."
#endif
#ifndef VAR_NAME
#error "VAR_NAME is not defined."
#endif

#define ARRAY_TYPE CONCAT(Array_, VAR_NAME)
struct ARRAY_TYPE{
    uint64_t size;
    VAR_TYPE *element;
    
    VAR_TYPE &operator [](uint64_t index)
    {
        assert(index < size);
        return element[index];
    }
};

static
ARRAY_TYPE CONCAT(ARRAY_TYPE, _init) (uint64_t size_in)
{
    ARRAY_TYPE result;
    result.element = (VAR_TYPE *)malloc(size_in * sizeof(VAR_TYPE));
    assert(result.element);
    result.size = size_in;
    return result;
}

#undef ARRAY_TYPE
#undef VAR_TYPE
#undef VAR_NAME
Allen Webster
478 posts / 2 projects

Heyo

Post your C/C++ macro tricks
3 years, 4 months ago Edited by Allen Webster on June 9, 2016, 4:24 p.m. Reason: Make parameters explicit
My favorite macro trick is for making something that looks like a resumable function call, sort of like a really light weight coroutine. So you can write code that says "ahh at this point I would like to return to the user some info, but then when they call me I want to resume right after the return point".


 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
31
32
33
34
35
struct State{
    int _pc_;
    
    // other variables that need to carry their value
    // over multiple resumes of the function call.
};

#define DrYield(c,v) do{ state->_pc_ = c; return(v); resume_##c:; } while(false)
#define DrReturn(v) do{ state->_pc_ = -1; return(v); } while(false)
#define DrCase(c) case c: goto resume_##c

void
foo(State *s, void *new_memory, File_Data file){
    switch (s->_pc_){
        DrCase(1);
        // ...
        DrCase(5);
    }
    
    // ... code stuff ...
    for (begin();check();increment()){
        if (need_memory_from_user()){
            DrYield(1, NeedMemory);
            // do something with new_memory
        }
        if (need_file_from_user()){
            DrYield(2, NeedFile);
            // do something with file
        }
        // ... code stuff ...
    }
    // ... code stuff ...
    
    DrReturn(state->success);
}


I did a video trying it out here if you want to see it in detail without using goto. The goto version is required if your resumable function might want to use switches itself though.

The only issue I don't like is having to list all the cases and giving each yield point a unique integer. I haven't found away around that using the goto version though.
474 posts
Post your C/C++ macro tricks
3 years, 4 months ago
Mr4thDimention
My favorite macro trick is for making something that looks like a resumable function call, sort of like a really light weight coroutine. So you can write code that says "ahh at this point I would like to return to the user some info, but then when they call me I want to resume right after the return point".


 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
31
32
33
34
35
struct State{
    int _pc_;
    
    // other variables that need to carry their value
    // over multiple resumes of the function call.
};

#define DrYield(c,v) do{ state->_pc_ = c; return(v); resume_##c:; } while(false)
#define DrReturn(v) do{ state->_pc_ = -1; return(v); } while(false)
#define DrCase(c) case c: goto resume_##c

void
foo(State *s, void *new_memory, File_Data file){
    switch (s->_pc_){
        DrCase(1);
        // ...
        DrCase(5);
    }
    
    // ... code stuff ...
    for (begin();check();increment()){
        if (need_memory_from_user()){
            DrYield(1, NeedMemory);
            // do something with new_memory
        }
        if (need_file_from_user()){
            DrYield(2, NeedFile);
            // do something with file
        }
        // ... code stuff ...
    }
    // ... code stuff ...
    
    DrReturn(state->success);
}


I did a video trying it out here if you want to see it in detail without using goto. The goto version is required if your resumable function might want to use switches itself though.

The only issue I don't like is having to list all the cases and giving each yield point a unique integer. I haven't found away around that using the goto version though.


if you don't mind using non-standard GCC extension you can use label as value: http://stackoverflow.com/q/1777990/731620

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
struct State{
    void* _pc_;
    //...
}
#define DrYield(v) do{ state->_pc_ = &&resume_## __LINE__; return(v); resume_##__LINE__:; } while(false)
#define DrReturn(v) do{ state->_pc_ = 0; return(v); } while(false)

void
foo(State *s, void *new_memory, File_Data file){
    if(s->_pc_) goto *s->_pc_;
    //...
}
Mārtiņš Možeiko
1979 posts / 1 project
Post your C/C++ macro tricks
3 years, 4 months ago Edited by Mārtiņš Možeiko on June 9, 2016, 10:07 p.m.
Computed goto statements are a very nice thing. They allow to create lower-overhead interpreters than a regular switch statement: http://eli.thegreenplace.net/2012...oto-for-efficient-dispatch-tables
Original Android Dalvik interpreter used computed goto (and few other tricks) to get better performance: https://android.googlesource.com/...2415b48bdef63/vm/mterp/README.txt

Unfortunately no MSVC support, until we get clang fronted :(
Casey Muratori
818 posts / 1 project

Casey Muratori is a programmer at Molly Rocket on the game 1935 and is the host of the educational programming series Handmade Hero.

Post your C/C++ macro tricks
3 years, 4 months ago
I am skeptical that these computed gotos are necessary to get the "improved" performance. For example, in MSVC you would just place an __assume(0) in the default: case of a switch and it would no longer emit the bounds-checking code, right? Has anyone done a more thorough analysis as to whether these are interesting?

- Casey
stephen goglin
20 posts

aka Quartertron

Post your C/C++ macro tricks
3 years, 4 months ago
One of my favourites is the X macro. A simple example is:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
#define MY_ENUMS \
    E(A)         \
    E(B)         \
    E(C)

#define E(e) Enum_ ## e,
typedef enum {
MY_ENUMS
} MyEnums;
#undef E

#define E(e) #e,
const char *MyEnumStrings[] = {
MY_ENUMS
};
#undef E


And of course you can do more complicated things.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
#define STATE_MACHINE                                 \
    X(Start,StartFunction,ParseState)                 \
    X(Parse,ParseSomeStuff,PrintState)                \
    X(Print,MaybeThisShouldBeGeneratedToo,ParseState) \
    /* yadda yadda yadda */

#define X(s,f,n) State_ ##s,
typedef enum {
    STATE_MACHINE
} MyStates;
#undef X

// much later in the code
#define X(s,f,n) case State_ ##s: if (f()) CurrentState = n; break;
    switch (CurrentState) {
        STATE_MACHINE
        default: exit(-42);
    }
#undef X


And so on. You can generate all kinds of different things from the initial list.

None
Mārtiņš Možeiko
1979 posts / 1 project
Post your C/C++ macro tricks
3 years, 4 months ago Edited by Mārtiņš Možeiko on June 10, 2016, 6:17 p.m.
I have used computed goto for gcc compiler before and it does creates better code.

Here's a micro-benchmark: https://gist.github.com/mmozeiko/...681dde202bd9bfe8fe185844858f04eaf
It's a tiny VM that performs "--x" operation billion times.

For gcc 5.3.0 it creates ~10% faster code for computed goto:
1
2
3
switch = 2132
goto   = 1913
improvement = 10%


Unfortunately gcc generates range check even with __builtin_unreachable in default case.
Ginger Bill
226 posts / 2 projects

I am ginger thus have no soul.

Post your C/C++ macro tricks
3 years, 4 months ago Edited by Ginger Bill on June 10, 2016, 9:03 a.m.
Here are some of my favourites:

 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
31
32
// Token to String
#define TO_STRING(x) #x

// Static Assertion
#define STATIC_ASSERT3(cond, msg) typedef char static_assertion_##msg[(!!(cond))*2-1]
#define STATIC_ASSERT2(cond, line) STATIC_ASSERT3(cond, static_assertion_at_line_##line)
#define STATIC_ASSERT1(cond, line) STATIC_ASSERT2(cond, line)
#define STATIC_ASSERT(cond)        STATIC_ASSERT1(cond, __LINE__)

// *_of "operators"
typedef ptrdiff_t isize;
// Signed sizeof is more useful
#define size_of(x) (isize)(sizeof(x))
// Prevents C++ arrays from being passed
#define count_of(x) ((size_of(x)/size_of(0[x])) / ((isize)(!(size_of(x) % size_of(0[x])))))
#define offset_of(Type, element) ((isize)&(((Type *)0)->element))
// C-Only
#define align_of(Type) offset_of(struct { char c; Type member; }, member)


// Swap
#define swap(Type, a, b) do { Type tmp = (a); (a) = (b); (b) = tmp; } while (0)


// Bit cast: Very similar to doing `*(T *)(&u)` but can be faster
#define BIT_CAST(dest, source) do { \
	STATIC_ASSERT(size_of(*(dest)) <= size_of(source)); \
	memcpy((dest), &(source), size_of(*dest)); \
} while (0)

// Cast - Easy to grep
#define cast(Type) (Type)



I have loads more in gb.h.