Handmade Network»Forums
Jack Mott
110 posts
Web Developer by day, game hobbyist by night.
Post your C/C++ macro tricks
Edited by Jack Mott on 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
12 posts / 1 project
I'm Dominik, a developer always loving to explore new ways of programming. Since my [b]handicap[/b] made me more-or-less impossible to do certain jobs, I've started with programming, as that's the only thing keeping me on [b]life[/b]. I always like to explore nature, going out with friends and reading some articles or books on the Internet. In my spare time I progress with [b]hobby[/b] and [b]community[/b] projects. My development [b]interests[/b] are mostly around desktop applications, [b]high-performance interactive[/b] apps especially. Taking advices from [b]Casey Muratori's Handmade Hero[/b] series, I aim for [b]optimization and code quality (KISS)[/b] altogether. I love listening to [b]Iron Maiden[/b] and playing [b]The Ultimate Doom[/b], they blend together very well.
Post your C/C++ macro tricks
Edited by Dominik Madarász on 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
110 posts
Web Developer by day, game hobbyist by night.
Post your C/C++ macro tricks
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
12 posts / 1 project
I'm Dominik, a developer always loving to explore new ways of programming. Since my [b]handicap[/b] made me more-or-less impossible to do certain jobs, I've started with programming, as that's the only thing keeping me on [b]life[/b]. I always like to explore nature, going out with friends and reading some articles or books on the Internet. In my spare time I progress with [b]hobby[/b] and [b]community[/b] projects. My development [b]interests[/b] are mostly around desktop applications, [b]high-performance interactive[/b] apps especially. Taking advices from [b]Casey Muratori's Handmade Hero[/b] series, I aim for [b]optimization and code quality (KISS)[/b] altogether. I love listening to [b]Iron Maiden[/b] and playing [b]The Ultimate Doom[/b], they blend together very well.
Post your C/C++ macro tricks
Thanks, I'll look into that one. It's nice to have this topic, always stuff to learn.
Mārtiņš Možeiko
2559 posts / 2 projects
Post your C/C++ macro tricks
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
Not too interesting, but funny:

1
#define private public
511 posts
Post your C/C++ macro tricks
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
6 posts
Post your C/C++ macro tricks
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
476 posts / 6 projects
Heyo
Post your C/C++ macro tricks
Edited by Allen Webster on 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.
511 posts
Post your C/C++ macro tricks
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
2559 posts / 2 projects
Post your C/C++ macro tricks
Edited by Mārtiņš Možeiko on
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
801 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
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
Mārtiņš Možeiko
2559 posts / 2 projects
Post your C/C++ macro tricks
Edited by Mārtiņš Možeiko on
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
222 posts / 3 projects
I am ginger thus have no soul.
Post your C/C++ macro tricks
Edited by Ginger Bill on
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.
511 posts
Post your C/C++ macro tricks
Edited by ratchetfreak on
cmuratori
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


It has to emit the bounds check because __pc__ can be anything (being passed in through pointer) and a switch has well defined behavior in all cases (a empty default being inserted if not present).

There may be hope if you make the default case be undefined behavior and let the optimizer run with that. This of course has the issue that you are relying on the optimizer's behavior for optimal code.

edit: and I should have looked up what __assume(0) does...