As an OOP dev this kind of horrifies me, even though it works okay (though it's surely not thread-safe?)
Nevertheless, even in C, I'd find it conceptually simpler to understand if the functions were written as pure functions, returning a tuple with (c, state) and passing the state back into the caller. Using non-idiomatic tricks and macros in this way is harder to read and understand.
Here's a POSIX compliant portable getopt() routine I wrote which uses this style. Is this hard to read? Note that it's several times shorter than every other implementation I've ever seen, and if I do say so myself I think it's eminently readable.
Nevertheless, even in C, I'd find it conceptually simpler to understand if the functions were written as pure functions, returning a tuple with (c, state) and passing the state back into the caller. Using non-idiomatic tricks and macros in this way is harder to read and understand.