Hi David,
On Fri, Jan 09, 2026 at 04:10:56PM +0100, David Brown wrote:
> On 09/01/2026 13:07, Alejandro Colomar via Gcc wrote:
> > #define strnulB(s) \
> > ({ \
> > auto s_ = s; \
> > s_ + strlen(s_); \
> > })
> >
> > The problem with strnulB() is that it has a local variable 's_'. This
> > means I can't pass an argument called s_. That is, the following call
> > doesn't work:
> >
> > strnulB(s_);
>
> That is always the risk of macros. Usually people just pick parameter names
> and local variable names that are very unlikely to collide. If you have
> -Winit-self (or -Werror=init-self) then collisions will be detected (as
> "auto s_ = s_;_" now gives a warning or error).
Yup, I have that enabled, and indeed is triggering.
> You can also use __LINE__ to generate unique symbols :
>
> #define strnulX(s) ({ \
> auto s__ ## __LINE__ = (s); \
> s__ ## __LINE__ + strlen(s__ ## __LINE__ ); \
> })
This doesn't solve it, because it is called from another macro, which
has the same __LINE__ value.
> But here you can probably just use a static inline function. It is, IME,
> always better to use a static inline function than a function-like macro
> when possible:
>
> static inline char * strnulY(char * s) {
> return s + strlen(s);
> }
I can't use this. I want something that preserves 'const', like the
C23 APIs using QChar.
I could in fact do both a function and a macro, plus all the magic for
doing QChar, but that's too much complexity, and would be better solved
with 'auto' in inline functions.
Have a lovely day!
Alex
>
>
> <https://godbolt.org/z/oGvcfbh14>
>
>
> >
> > Is there a way to implement something like this?:
> >
> > #define strnulC(s) \
> > ({ \
> > static_assert(!has_side_effects(s)); \
> > s + strlen(s); \
> > })
> >
> > If there's no way, it would be interesting to add compound literals of
> > function type to achieve this:
> >
> > #define strnulD(...) \
> > ((static inline auto \
> > (auto s)) \
> > { \
> > return s + strlen(s); \
> > }(__VA_ARGS__))
> >
> > Which guarantees that the argument is evaluated once.
> >
>
> Do you need your macro here to work with different types? I'm not sure how
> that could make sense, since "strlen" is not generic and always treats its
> parameter as a char*.
>
> If you do need something that can work with different types and you want to
> use functions to avoid possible issues with macro parameters, you can use
> _Generic :
>
> #define strnulX(s) _Generic((s), \
> char * : strnulX_char(s), \
> char16_t * strnulX_char16(s), \
> char32_t * strnulX_char32(s)
> )(s)
>
> Then define functions strnulX_char, strnulX_char16, and strnulX_char32 as
> separate functions. (_Generic does not evaluate its argument, so
> side-effects don't matter to it.)
>
>
--
<https://www.alejandro-colomar.es>
signature.asc
Description: PGP signature
