Hi Chris,
On Fri, Jan 09, 2026 at 03:39:28PM +0000, Christopher Bazley wrote:
>
> Hi Alex,
>
> On 09/01/2026 12:07, Alejandro Colomar via Gcc wrote:
> > Hi!
> >
> > I'm trying to find a way to verify that an expression (usually passed as
> > an argument to a macro) has no side effects. Is this possible?
> >
> > Let's say I want to implement strnul():
> >
> > #define strnulA(s) (s + strlen(s)) // Problem: evaluates twice
> >
> > #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_);
> >
> > Is there a way to implement something like this?:
> >
> > #define strnulC(s) \
> > ({ \
> > static_assert(!has_side_effects(s)); \
> > s + strlen(s); \
> > })
>
> I think it would be impossible to implement such a feature perfectly because
> the expression 's' might invoke functions that are defined in other
> translation units (even source code that hasn't been written yet). Any
> implementation would need to be conservative.
>
> > 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.
>
> I don't favour statement literals precisely because they provide a mechanism
> for creating fake encapsulation. The 'fakeness' comes from the point that
> you raised: even if the programmer diligently assigns each macro argument to
> a local variable (which is a pain in itself), all of the identifiers in the
> enclosing scope are still in scope.
>
> I would solve the same problem like this, except that I probably wouldn't
> bother with the templates for such a trivial function:
>
> #define STRNUL_TEMPLATE(NAME, QCHAR) \
> static inline QCHAR *NAME(QCHAR *s) \
> { \
> return s + strlen(s); \
> }
>
> STRNUL_TEMPLATE(strnulc, const char)
> STRNUL_TEMPLATE(strnul, char)
>
> #define STRNUL(S) \
> _Generic(S, \
> char const *: strnulc, \
> char *: strnul)(S)
It can be done simpler than this. I've implemented the QChar APIs from
libc as simple wrappers around the old functions:
#define __QVoidptrof(p) typeof(1?(p):(void*){0})
#define __QCharptrof(s) typeof \
( \
_Generic((__QVoidptrof(s)){0}, \
const void *: (const char *) 0, \
void *: (char *) 0 \
) \
)
define strchr(s, chr) ((__QCharptrof(s)) strchr(s, chr))
Essentially the same could be done with strnul() by just adding the
function definition:
#define strnul(s) ((__QCharptrof(s)) strnul(s))
char *
(strnul)(const char s)
{
return s + strlen(s);
}
But I was hoping I could do it even simpler. A function taking and
returning 'auto' would certainly be simpler. Maybe I'm trying to
simplify too much, though.
>
> int main(void)
> {
> char s[] = "Mutable",
> *ps = STRNUL(s);
> const char cs[] = "Immutable",
> *pcs = STRNUL(cs);
> return 0;
> }
>
> I do support function literals as a more scenic alternative to lambdas, but
> I don't believe the proposal currently before WG14
> (https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3679.pdf) incorporates
> the idea of return type inference. I'd expect typeof
> to be used for that purpose instead:
>
> #define STRNUL(S) \
> (static typeof(S) (typeof(S) s)) \
> { \
> return s + strlen(s); \
> }(S)
>
> Or maybe, in future C:
>
> #def STRNUL(S)
> (static typeof(S) (typeof(S) s))
> {
> return s + strlen(s);
> }(S)
> #enddef
>
> Note that typeof never evaluates its operand and it is much simpler than C++
> templates.
Have a lovely day!
Alex
>
> --
> Christopher Bazley
> Staff Software Engineer, GNU Tools Team.
> Arm Ltd, 110 Fulbourn Road, Cambridge, CB1 9NJ, UK.
> http://www.arm.com/
--
<https://www.alejandro-colomar.es>
signature.asc
Description: PGP signature
