[TUHS] To NDEBUG or not to NDEBUG, that is the question

Dan Cross via TUHS tuhs at tuhs.org
Fri Oct 17 22:22:23 AEST 2025


On Fri, Oct 17, 2025 at 7:50 AM Aharon Robbins via TUHS <tuhs at tuhs.org> wrote:
> Hello All.
>
> A bit off-topic, perhaps, but thoughts from this crowd would be welcome.
>
> I just finished tracking down a bug in gawk that was only noticed
> because the Windows port is built without -DNEBUG, causing assertions
> (via assert(3)) to be included in the code.  The regular *nix build
> defines NDEBUG, so that assertions are not included in the regular,
> "production" build.
>
> Now, I can understand why assert() and NDEBUG work the way they do.
> Particularly on the small PDP-11s on which C and Unix were developed,
> it made sense to have a way to remove assertions from code that would
> be installed for all users.
>
> However, I'm starting to wonder.  Are my habits from yesteryear (defining
> NDEBUG by default) getting in the way of my being able (or users being
> able) to find bugs and report them?  Should I remove the defining of
> NDEBUG from the default build?  In particular, given the many orders of
> magnitude increase in CPU and memory of modern systems, is it likely
> that assertions won't really affect performance all that much?
>
> I'm starting to think that the answer is yes, it's time to remove
> NDEBUG.  But I'm curious what the experienced developers here
> might think.
>
> Much thanks,

My own two bit non-answer: it depends on what you're asserting and how often.

I think whether or not one compiles out assertions should be guided by
profiling: if setting NDEBUG results in a substantial speedup, and
that's important (ie, the speedup is a critical path or of some kind),
then set NDEBUG. On the other hand, if the performance difference is
negligible, or even just small, I would preserve them. I do think our
default these days should be to leave assertions in unless it's shown
to be a substantial drag.

One must question whether `assert` is the right thing or not, though;
as an interface, it's pretty limited: a thing can either be true or
not, but any surrounding information is not preserved; for example,
one often wants to assert whether two things are equal, but if they
are not, it's often very useful to know what the actual values are:
`assert` doesn't give you that.  One also wishes for a non-optional
assertion that is always executed; perhaps `assert_always` or
something (the illumos kernel inherited `ASSERT` and `VERIFY` from
Solaris; `ASSERT` is compiled-out in non-debug builds, but `VERIFY` is
always executed).  I suppose the alternative in both cases is an
explicit check against an expected condition and calling some kind of
failure routine if the condition is not met.

I do have a history question, though; `assert` seems to have found its
way into Unix in 7th Edition.  It's used most heavily in `refer`, and
appears in exactly one place in `sh` (but `sh` defines it to just be
`;`). A few other places define a macro called `ASSERT` (or a
variation of that) that does more or less the same thing: `struct`,
`uucp`, and a couple of places in the Fortran-77 compiler/library.
There doesn't appear to be any history of it prior to v7.  Who added
it, and why?

        - Dan C.


More information about the TUHS mailing list