Побочные эффекты в генерических выражениях
Я экспериментирую с новым ключевым словом _Generic
и наткнулся на специальный случай, касающийся нескольких оценок. См. Следующее:
#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');
}
Это компилирует штраф и дает ожидаемый результат с помощью GCC:
$ gcc -std=c11 -Wall plusplus.c -o plusplus
$ ./plusplus
foo
С другой стороны, Clang выводит большое предупреждение о гудении:
$ 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)
...
Однако результат будет таким, как ожидалось:
$ ./plusplus
foo
Я проверил проект стандарта, в котором говорится (на стр. 97 PDF):
Контролирующее выражение общего выбора не оценивается.
Это, по-видимому, точно решает проблему побочных эффектов в макросах (например, MIN
и MAX
).
Теперь, могу ли я безопасно игнорировать предупреждение Клана, или я ошибаюсь?
Ответы
Ответ 1
Как я уже упоминал в комментариях, вы опубликовали вопрос о двух неделях после того, как ошибка была исправлена в стволе Clangs. См. Ревизию rL223266 (3 декабря 2014 года). Исправление включено в Clang 3.6.
Теперь, могу ли я безопасно игнорировать предупреждение Клана, или я ошибаюсь?
Мы уже знаем, что вы правы, поэтому вот способ игнорировать прагмы в Clang для
будущее:
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunsequenced"
write_char(*s++);
#pragma clang diagnostic pop
Чтобы не повторять его при каждом использовании макроса, вы можете поместить _ Pragma в его тело:
#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")
Ответ 2
Кажется, это была ошибка. Теперь он был решен, поскольку clang
3.6 дальше, как показано здесь.