Path: csiph.com!eternal-september.org!reader02.eternal-september.org!.POSTED!not-for-mail From: Tim Rentsch Newsgroups: comp.lang.c Subject: Re: Verbose assert Date: Mon, 25 Apr 2022 15:41:12 -0700 Organization: A noiseless patient Spider Lines: 59 Message-ID: <86h76g6b1z.fsf@linuxsc.com> References: <87r17xafpo.fsf@bsb.me.uk> Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Injection-Info: reader02.eternal-september.org; posting-host="e7f354bf3c65e91fece722955444236f"; logging-data="9425"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX190+1FizVqyW/s1mpLUQ9SVwYQjqIsLwyQ=" User-Agent: Gnus/5.11 (Gnus v5.11) Emacs/22.4 (gnu/linux) Cancel-Lock: sha1:PPgSC5A0SxFiB/A14moMIvd0Qxw= sha1:KmieHqutIqsBEToSeIAQmXRCt7I= Xref: csiph.com comp.lang.c:165936 Ben Bacarisse writes: > Mehdi Amini writes: > > It seems you want something like this: > > #include > #include > #include > > void my_assert(int cond, const char *fmt, ...) > { > if (!cond) { > va_list al; > va_start(al, fmt); > vfprintf(stderr, fmt, al); > va_end(al); > exit(EXIT_FAILURE); > } > } > > #define MY_ASSERT(cond, fmt, ...) \ > my_assert(cond, "*** \"%s\" line %d: " fmt, \ > __FILE__, __LINE__, __VA_ARGS__) > > int main(void) > { > int a = 41, b = 42; > MY_ASSERT(a == b, "%d != %d as required.\n", a, b); > } > > Note that this uses string concatenation to build the format, but you > can write a version that will work with non-literal formats. Just a few comments on this. One, the filename and line number can be combined to produce a single string literal at compile time, using the preprocessor and "gluing together" of string literals (and which can then be combined with the format in the same way as above). Two, usually it's a bad idea in cases like this to expand the macro into a single function call, because variadic functions cannot be inlined. Three, another problem along those lines is that the function arguments are evaluated even if the tested condition succeeds. Combining points two and three, we might revise the macro definition to something like (disclaimer: not tested) #define MY_ASSERT( test, ... ) ( \ ! (test) \ ? my_assert_failed( FILE_LINE_STRING() __VA_ARGS__ ) \ : 0 \ ) (Note that the format string, if any, is part of __VA_ARGS__ and will be combined with the FILE_LINE_STRING() string per the rules of combining adjacent string literals.)