XMacros
- 01 May 2026
- Manuel Capel
- Tags: C programming
XMacros are a way for the C preprocessor to process lists. They are quite unknown. Many would probably qualify them as Macro wizardry, but their logic makes sense once understood. Anyway, it’s a good trick to know. We will see how it work along a simple example: find the position of the first bit set in a 8-bits integer. This is called ffs (find first set) or clz (count leading zeros).
Foreword: CLZ algorithm
An 8-bits integer u is represented by a sequence of 8 bits set to 0 or 1.
If it contains a 1, then u & -u will contain only one 1,
at the position of the first bi set to 1 in u.
Thus in order to find the position of this 1, we have to test 7 possibilities:
is u & -u equals to 1 << 1 or to 1 << 2, …, or to 1 << 7.
For this, we will use a switch branching for those 7 values.
N.B.: if u == 0 or (u & -u) == 1, we return 0.
Syntax
List inside Function
Here we first define the list of elements to process:
1
2
#define U8CLZ_LIST \
U8CLZ(1) U8CLZ(2) U8CLZ(3) U8CLZ(4) U8CLZ(5) U8CLZ(6) U8CLZ(7)
Note that each element is wrapped around U8CLZ(),
which will be the function applied to each element.
Now we define this U8CLZ(), and tell it to apply to each element in U8CLZ_LIST:
1
2
3
4
5
6
#define U8CLZ(u) \
case 1 << u: \
ret = u; \
break;
U8CLZ_LIST
#undef U8CLZ
Later if we want we can also reuse U8CLZ_LIST with another U8CLZ() macro function.
If we compile with the -L option to get the expanded macros,
we can see this expands to:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
case 1 << 1:
ret = 1;
break;
case 1 << 2:
ret = 2;
break;
case 1 << 3:
ret = 3;
break;
case 1 << 4:
ret = 4;
break;
case 1 << 5:
ret = 5;
break;
case 1 << 6:
ret = 6;
break;
case 1 << 7:
ret = 7;
break;
Instead of writing this fastidous list and having it in our code, we can neatly let the compiler generate it for us.
To summarize, we have compacter, (imho) cleaner code, in a list we can re-use in other macro functions.
Function inside List
The code above is wrapped in a vanilla C function called u8clz().
Here we want to test this function for various values.
1
2
#define FOR_TEST_VALUES(DO) \
DO(1) DO(40) DO(255) DO(18) DO(1 << 4)
This time, the values are defined through a macro function taking DO as argument,
and this DO wraps each value in the list.
Note: by convention, such a function is prefixed by FOR_.
Then we define the macro function that will play the role of DO:
1
2
#define PRINT_VALUE_AND_CLZ(v) \
printf("u8clz(%u): %u\n", v, u8clz(v));
Which, for a given v, printf() v and u8clz(v).
Now we can proceed to the final call:
1
FOR_TEST_VALUES(PRINT_VALUE_AND_CLZ)
This expands then to:
1
2
3
4
5
printf("u8clz(%u): %u\n", 1, u8clz(1));
printf("u8clz(%u): %u\n", 40, u8clz(40));
printf("u8clz(%u): %u\n", 255, u8clz(255));
printf("u8clz(%u): %u\n", 18, u8clz(18));
printf("u8clz(%u): %u\n", 1 << 4, u8clz(1 << 4));
Personally I find this “function inside list” approach cleaner, since function and list are more decoupled here: you don’t have to wrap the values inside a function named after the actual function that will process them.
Conclusion
When you run the program, it looks fine:
1
2
3
4
5
l2u8(1): 0
l2u8(40): 3
l2u8(255): 0
l2u8(18): 1
l2u8(16): 4
X-Macros are a neat nice little trick doing small wonders, good to have in your toolbox. The complete code is available on this snippet. Thanks for reading!