Подтвердить что ты не робот

Побочные эффекты в генерических выражениях

Я экспериментирую с новым ключевым словом _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).

Теперь, могу ли я безопасно игнорировать предупреждение Клана, или я ошибаюсь?

4b9b3361

Ответ 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 дальше, как показано здесь.