Что должен генерировать #__VA_ARGS__, если аргументы не переданы?

Пример кода:

#define FOO(...) You passed: #__VA_ARGS__
FOO(1,2,3)
FOO()

Предварительно обработайте Visual C++ (версия 14 CTP), получите:

You passed: "1,2,3"
You passed:

В последней строке #__VA_ARGS__ превращается в ничто. Я бы предпочел, чтобы он превратился в "".

Есть ли определенная ссылка на то, что должно произойти? Я много гуглил, но не мог найти.

Любой предложенный обходной путь также будет полезен.


person Bryan    schedule 01.07.2014    source источник
comment
Это может быть не указано в стандарте. В настоящее время я получаю "", когда запускаю препроцессор gcc.   -  person merlin2011    schedule 01.07.2014
comment
Вы просматривали предварительно обработанный исходный код или есть шанс, что вы неправильно интерпретируете вывод своей тестовой программы?   -  person PlasmaHH    schedule 01.07.2014
comment
Это не имеет значения, не так ли? Вы всегда можете объединить результат в любую строку: "Hello: " FOO() "!\n"   -  person Kerrek SB    schedule 01.07.2014


Ответы (2)


Согласно 6.10.3.2 Оператор # (C11):

Семантика

2 - [...] Литерал строки символов, соответствующий пустому аргументу, равен "". [...]

Поэтому я думаю, что MSVC здесь неверен.

Я бы обошёл это, используя конкатенацию строковых литералов:

#define FOO(...) You passed: "" #__VA_ARGS__
person ecatmur    schedule 01.07.2014
comment
Что ж, VC++ никогда не претендовал на полную реализацию C99 или C11, так что трудно сказать, что это неправильно; это просто другое. - person Matthieu M.; 01.07.2014

Параграф в стандарте (ISO14882:2011(e)) немного длинный, но вполне понятный:

16.3.2 Оператор #

2 литерал символьной строки — это литерал строки без префикса. Если в списке замещения параметру непосредственно предшествует токен предварительной обработки #, оба они заменяются токеном предварительной обработки с литералом из одной символьной строки, который содержит написание последовательности токенов предварительной обработки для соответствующего аргумента. Каждое появление пробела между токенами предварительной обработки аргумента становится одиночным символом пробела в литерале строки символов. Пробел перед первым токеном предварительной обработки и после последнего токена предварительной обработки, содержащего аргумент, удаляется. В противном случае исходное написание каждого токена предварительной обработки в аргументе сохраняется в литерале строки символов, за исключением специальной обработки для создания написания строковых литералов и символьных литералов: символ \ вставляется перед каждым символом " и \ символьного литерала. или строковый литерал (включая разделительные символы "). Если полученная замена не является допустимым литералом строки символов, поведение не определено. Литералом строки символов, соответствующим пустому аргументу, является "". Порядок вычисления операторов # и ## не указан.

И с тех пор

16.3.1 Замена аргумента

2 Идентификатор __VA_ARGS__, встречающийся в списке замены, должен рассматриваться как параметр, а переменные аргументы должны формировать токены предварительной обработки, используемые для его замены.

это то же самое для варагов, что и для обычных параметров.

person PlasmaHH    schedule 01.07.2014
comment
Спасибо; Я попробовал это с простым аргументом (#define FOO(x)), и он ведет себя так же. - person Bryan; 01.07.2014
comment
@Bryan: Тогда мне это кажется ошибкой. Но людям нравится называть такие вещи функциями, поэтому, если вы не спросите их (заполнив отчет об ошибке), мы никогда не узнаем. - person PlasmaHH; 01.07.2014