C preprocessor utilities
zen.h is a collection of C preprocessor macros. Right now it offers only a small framework for managing a 32-bit counter purely via the C preprocessor, but it might expand in the future.
There are two main reasons for implementing a novel counter for the C preprocessor other than the built-in (and non-standard) __COUNTER__
. The first reason is that __COUNTER__
is not flexible: when two or more headers use it, the values that this yields are not predictable. The second and most important reason is that __COUNTER__
is not reusable and gets increased every time it is invoked, making the storage of its yielded values within the preprocessor environment virtually impossible.
With these two reasons in mind, this framework has been designed to implement a counting macro that increments only when an incrementing function is explicitly called on it, but that keeps otherwise its current value; and that is able to deal with infinite identifiers, in order to avoid conflicts between different headers that might need to use a counter separately.
Unfortunately the C preprocessor is a tough beast, and the best way to implement such a counter and safely bind it to a 32-bit unsigned type is through fixed-length hexadecimal numbers. This does not produce any particular behavior when the values yielded by the counter are used as literal integers, but does produce a different result compared to the one produced by the built-in __COUNTER__
when these values are used to create unique identifiers.
Within this implementation it is possible to set a counter to any 32-bit arbitrary value other than zero or a natural increment by providing its hexadecimal digits (see macro ZEN_COUNTER_PARSE_HEX()
).
#include <stdio.h>
#include "zen.h"
int main() {
#define FIRST_VALUE ZEN_COUNTER_NEW()
printf("%u\n", ZEN_COUNTER_AS_NUMBER(FIRST_VALUE)); // "0"
#define SECOND_VALUE ZEN_COUNTER_NEXT(FIRST_VALUE)
printf("%u\n", ZEN_COUNTER_AS_NUMBER(SECOND_VALUE)); // "1"
#define THIRD_VALUE ZEN_COUNTER_NEXT(SECOND_VALUE)
printf("%u\n", ZEN_COUNTER_AS_NUMBER(THIRD_VALUE)); // "2"
#define OTHER_COUNTER ZEN_COUNTER_PARSE_HEX(0, 0, 0, 4, F, 3, B, 6)
printf("%u\n", ZEN_COUNTER_AS_NUMBER(OTHER_COUNTER)); // "324534"
#define FIFTH_VALUE ZEN_COUNTER_NEXT(OTHER_COUNTER)
printf("%u\n", ZEN_COUNTER_AS_NUMBER(FIFTH_VALUE)); // "324535"
#define SIXTH_VALUE ZEN_COUNTER_NEXT(THIRD_VALUE)
printf("%u\n", ZEN_COUNTER_AS_NUMBER(SIXTH_VALUE)); // "3"
return 0;
}
ZEN_COUNTER_NEW()
Returns a new zen counter set to 0
.
ZEN_COUNTER_PARSE_HEX(HEX1, HEX2, HEX3, HEX4, HEX5, HEX6, HEX7, HEX8)
Returns a new zen counter set to a given value.
-
HEX1
, …HEX8
-
The eight hexadecimal digits needed to represent a 32-bit unsigned integer.
ZEN_COUNTER_NEXT(COUNTER)
Returns a new zen counter that equals the zen counter passed as argument plus one.
-
COUNTER
-
The counter to use as base of increment.
ZEN_COUNTER_AS_NUMBER(COUNTER)
Returns the literal numerical representation of the zen counter passed as argument.
-
COUNTER
-
The counter to convert to a literal unsigned integer.
ZEN_COUNTER_AS_IDENTIFIER(COUNTER, PREFIX)
Returns a new unique identifier based on the concatenation of the prefix and the zen counter passed as arguments.
-
COUNTER
-
The zen counter to use as unique suffix.
-
PREFIX
-
The prefix to which the counter will be concatenated.
ZEN_COUNTER_AS_HEX_STRING(COUNTER)
Returns a new literal string containing the hexadecimal representation of COUNTER
(without the 0x
prefix).
-
COUNTER
-
The counter to stringify.