I'm doing some experiments with the new _Generic
keyword and stumbled upon a special case regarding multiple evaluations. See the following:
#include <stdio.h> #define write_char(c) _Generic(c, char: putchar, const char: putchar)(c) int main(void) { const char *s = "foo"; write_char(*s++); write_char(*s++); write_char(*s++); putchar('\n'); }
This compiles fine and produces the expected result with GCC:
$ gcc -std=c11 -Wall plusplus.c -o plusplus $ ./plusplus foo
On the other hand, Clang outputs a big honking warning:
$ clang -std=c11 plusplus.c -o plusplus plusplus.c:9:18: warning: multiple unsequenced modifications to 's' [-Wunsequenced] write_char(*s++); ^~ plusplus.c:3:32: note: expanded from macro 'write_char' #define write_char(c) _Generic(c, char: putchar, const char: putchar)(c) ...
Yet the result is as expected:
$ ./plusplus foo
I checked the draft of the standard, which says (at p. 97 of the PDF):
The controlling expression of a generic selection is not evaluated.
This seems to precisely address the problem of side-effects in macros (e.g., MIN
and MAX
).
Now, can I safely ignore Clang's warning, or am I wrong?
Generic medicines use the same active ingredients as brand-name medicines and work the same way, so they have the same risks and benefits as the brand-name medicines.
Myth 4: Generic medications are more likely to cause side effects. The FDA requires that generics have the same clinical risks and benefits as their brand-name counterparts, so one version shouldn't cause more side effects than the other should.
Generic medicines work the same as brand-name medicines A generic medicine is required to be the same as a brand-name medicine in dosage, safety, effectiveness, strength, stability, and quality, as well as in the way it is taken. Generic medicines also have the same risks and benefits as their brand-name counterparts.
In medicine, a side effect is an effect, whether therapeutic or adverse, that is secondary to the one intended; although the term is predominantly employed to describe adverse effects, it can also apply to beneficial, but unintended, consequences of the use of a drug.
As I mentioned in comments, you posted the question about two weeks after the bug was fixed in Clangs trunk. See revision rL223266 (December 3 2014). The fix is included in Clang 3.6.
Now, can I safely ignore Clang's warning, or am I wrong?
We already know that you're right, so here is a way to ignore pragmas in Clang for the future:
#pragma clang diagnostic push #pragma clang diagnostic ignored "-Wunsequenced" write_char(*s++); #pragma clang diagnostic pop
To do not repeat it on every use of the macro, you could put _Pragma in its body:
#define write_char(c) \ _Pragma("clang diagnostic push") \ _Pragma("clang diagnostic ignored \"-Wunsequenced\"") \ _Generic(c, char: putchar, const char: putchar)(c) \ _Pragma("clang diagnostic pop")
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With