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)

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.

--
Christopher Bazley
Staff Software Engineer, GNU Tools Team.
Arm Ltd, 110 Fulbourn Road, Cambridge, CB1 9NJ, UK.
http://www.arm.com/

Reply via email to