You're right that assert() isn't the most reliable way to do this (programs have to work whether or not assert() is a no-op; that's the point of assert).
On most platforms, you can just rig malloc to do the abort itself instead of failing --- either with configuration or by preloading a wrapper malloc. Some very, very large shops do exactly this.
Another very common idiom is "xmalloc", which does the malloc/if/abort dance. But xmalloc() misses every place where libraries call malloc(); the most obvious example is strdup(), but the more pernicious issue is 3rd party code that can't know to use x-whatever().
Calling malloc and then immediately assert()'ing success is a reasonable shorthand. That exact same code can be made safe on any mainstream platform just by changing malloc's configuration.
† On general-purpose platforms; I know things are more complicated on embedded platforms.
Do you have an example of documentation that shows how to configure malloc to do some cleanup in the case of failure? Based on the Linux manpages I can't really see any obvious way to do this short of preloading some kind of malloc wrapper that's custom-written for the application.
So what I'd recommend is, grab Jason Evans' jemalloc package and use that (it's good enough for Facebook!).
The compiler will realise that:
assert(assert(line != NULL && longest != NULL && "memory error");
Is equivalent to: assert(line != NULL && longest != NULL);
But there doesn't seem anything wrong with that.(That doesn't make these particular asserts an error).
#ifdef NDEBUG
#define assert(e) ((void)0)
#else
#define assert(e) \
((void) ((e) ? 0 : __assert (#e, __FILE__, __LINE__)))
#define __assert(e, file, line) \
((void)printf ("%s:%u: failed assertion `%s'\n", file, line, e), abort())
So, if NDEBUG ("no debug") is defined, which it is if optimizations are turned on, asserts become a no-op.http://c.learncodethehardway.org/book/learn-c-the-hard-waych...