«ISO C99 требует по крайней мере один аргумент для макроса с переменным числом аргументов». При специальном использовании макросов c11 и -Wno-variadic

У меня есть простой: #define log(text, ...) fprintf(stderr, "stuff before" text "stuff after", ## __VA_ARGS__); который запускает: error: ISO C99 requires at least one argument for the "..." in a variadic macro [-Werror]

Должно ли использование -std=c11 и -Wno-variadic-macros не исправлять эту ошибку/предупреждение?

Добавление #pragma GCC system_header в заголовочный файл перед определением журнала устраняет эту проблему (не обязательно проверял, работает ли выведенный двоичный файл...), но это кажется хакерским, и я не совсем уверен в последствиях этого.

Вот пример ожидаемого поведения: https://stackoverflow.com/a/31327708/5698848

От GNU

-Wvariadic-macros

    Warn if variadic macros are used in ISO C90 mode, or if the GNU alternate syntax is used in ISO C99 mode.
    This is enabled by either -Wpedantic or -Wtraditional.
    To inhibit the warning messages, use -Wno-variadic-macros.

Любая идея об элегантном решении, чтобы остановить это предупреждение/ошибку из легального кода GNU GCC C? Почему он говорит, что я использую C99, и почему не работает флаг отключения предупреждения для C99? Линия выглядит так:

gcc -c src/file.c -Wall -Werror -Wextra -pedantic -Wfloat-equal -Wwrite-strings -Wcast-qual -Wunreachable-code -Wcast-align -Wstrict-prototypes -Wundef -Wshadow -Wstrict-aliasing -Wstrict-overflow -Wno-variadic-macros -g3 -std=c11 -O2 -flto -Iinclude/ -MMD -MF depend/file.d -o bin/file.o

Обратите внимание, что -pedantic действительно является виновником.


MCVE

c.c

#include <stdio.h>
#include <stdlib.h>

#define log(text, ...) fprintf(stderr, "stuff before" text "stuff after", ## __VA_ARGS__);

int main(void)
{

    log("should work, but doesn't");
    log("works fine: %s", "yep");

    return EXIT_SUCCESS;
}

Makefile

all:
    gcc c.c -Wall -Werror -Wextra -pedantic -Wfloat-equal -Wwrite-strings -Wcast-qual -Wunreachable-code -Wcast-align -Wstrict-prototypes -Wundef -Wshadow -Wstrict-aliasing -Wstrict-overflow -Wno-variadic-macros -g3 -std=c11 -O2

Примечание. Удаление педантичных компиляций нормально — gcc (Ubuntu 5.4.0-6ubuntu1~16.04.4) 5.4.0 20160609


person jake    schedule 16.05.2017    source источник
comment
#define log(text, ...) fprintf(stderr, "stuff before" text "stuff after", ## __VA_ARGS__); — сложный макрос. Если text не является строковым литералом, он сломан, чего нельзя ожидать от вызова в стиле printf.   -  person Andrew Henle    schedule 16.05.2017
comment
Почему вы читаете документацию от GCC 2.95.2? Это древнее.   -  person aschepler    schedule 16.05.2017
comment
Эта часть не обязательно важна. Вы едва ли не первый, кто написал макрос ведения журнала с переменным числом переменных. Если вы не думаете, что то, что я сказал, важно, вы упустили связь со своей проблемой. И как только вы решите это, вы также получите макрос, который будет иметь гораздо больше смысла, если вы посмотрите на него через несколько месяцев или даже лет...   -  person Andrew Henle    schedule 16.05.2017
comment
##__VA_ARGS__ является расширением GCC. Если вы укажете соответствие ISO, вы не получите расширения gcc (в основном). Вы пытались указать соответствие GNU, например. -std=gnu11 ?   -  person M.M    schedule 16.05.2017
comment
Кроме того, вы должны опубликовать MCVE (я не могу воспроизвести вашу ошибку, пытаясь использовать различные версии gcc)   -  person M.M    schedule 16.05.2017
comment
Что вы подразумеваете под переопределением моего заданного стандарта. Вы предоставили флаг -std=c11, и вы получаете поведение C11. Что вы ожидали?   -  person M.M    schedule 16.05.2017
comment
Спецификация одинакова в C99 и C11. Вероятно, gcc не удосужился изменить сообщение об ошибке в соответствии с вашим флагом. Вы можете сообщить об ошибке, хотя я сомневаюсь, что кому-то будет достаточно времени, чтобы добавить эту функцию...   -  person M.M    schedule 16.05.2017
comment
Чтобы сделать вывод, является ли что-то одинаковым для обоих стандартов, вы читаете документы стандартов.   -  person M.M    schedule 16.05.2017
comment
@jake: Вы должны перечитать, что на самом деле означает -Wpedantic (-pedantic то же самое, но устарело по очевидным причинам).   -  person too honest for this site    schedule 16.05.2017


Ответы (2)


В ISO C99 и C11, когда вы определяете макрос, например:

#define log(text, ...)   something

тогда любой вызов макроса должен принимать как минимум 2 аргумента. Ваш код неправильно сформирован в ISO C (все версии).

Флаг GCC -pedantic согласно документации. означает:

Выдавать все предупреждения, требуемые строгим ISO C и ISO C++; отклонять все программы, использующие запрещенные расширения, и некоторые другие программы, не соответствующие ISO C и ISO C++. Для ISO C следует версия стандарта ISO C, указанная любой используемой опцией -std.

Разработчики GCC решили включить код, использующий это расширение, в «некоторые другие программы, не соответствующие ISO C». Если вы хотите использовать это нестандартное расширение в своем коде, вам не следует использовать флаг -pedantic.

Разработчики GCC также не удосужились изменить текст сообщения об ошибке, чтобы сказать «ISO C11 запрещает ...», если вы запросили соответствие C11. Если это касается вас, возможно, вы могли бы представить патч.


Что касается -Wno-variadic-macros, документация такова:

Предупреждать, если макросы с переменным числом переменных используются в режиме ISO C90 или если используется альтернативный синтаксис GNU в режиме ISO C99.

Под «альтернативным синтаксисом GNU» подразумевается синтаксис GNU для включения вариативных макросов в первую очередь до C99, как описано в документация GCC (а не расширение для предоставления меньшего количества аргументов, чем минимум):

GCC уже давно поддерживает вариативные макросы и использует другой синтаксис, который позволяет вам давать имена переменным аргументам, как и любому другому аргументу. Вот пример:

#define debug(format, args...) fprintf (stderr, format, args)
person M.M    schedule 16.05.2017

Вот решение для C99:

#define debug_print(...) \
        do { fprintf(stderr, "%s:%d:%s(): ",__FILE__, __LINE__, __func__);\
             fprintf(stderr, __VA_ARGS__); } while (0)
person jean-loup    schedule 15.06.2018