Составные литералы и функционально-подобные макросы: ошибка в gcc или стандарт Си? - PullRequest
8 голосов
/ 06 апреля 2011

В C99 у нас есть составные литералы, и они могут быть переданы в функции как в:

f((int[2]){ 1, 2 });

Однако, если f не является функцией, а скорее похожим на функцию макросом, gcc преобразует это из-за того, что препроцессор анализирует его не как один аргумент, а как два аргумента: "(int[2]){ 1" и "2 } ».

Это ошибка в gcc или в стандарте C? Если это последнее, то это в значительной степени исключает прозрачное использование функционально-подобных макросов, что кажется огромным недостатком ...

Редактировать: В качестве примера можно ожидать, что следующий фрагмент программы будет соответствовать:

fgetc((FILE *[2]){ f1, f2 }[i]);

Но поскольку fgetc может быть реализован в виде макроса (хотя и необходим для защиты своего аргумента, а не для его оценки более одного раза), этот код на самом деле будет некорректным. Это кажется мне удивительным.

Ответы [ 3 ]

8 голосов
/ 06 апреля 2011

Эта «ошибка» существует в стандарте с C89:

#include <stdio.h>

void function(int a) {
    printf("%d\n", a);
}

#define macro(a) do { printf("%d\n", a); } while (0)

int main() {
    function(1 ? 1, 2: 3); /* comma operator */
    macro(1 ? 1, 2: 3);    /* macro argument separator - invalid code */
    return 0;
}

На самом деле я не просматривал стандарт, чтобы проверить этот синтаксический анализ, я взял слово gcc для него, но неофициально необходимость соответствия : каждому ? превосходит как приоритет оператора, так и синтаксис списка аргументов для сделать первое заявление работать. Нет такой удачи со вторым.

4 голосов
/ 06 апреля 2011

Это в соответствии со стандартом C, аналогично тому, как в C ++, следующая проблема:

f(ClassTemplate<X, Y>) // f gets two arguments:  'ClassTemplate<X' and 'Y>'

Если в C99 разрешено добавлять дополнительные скобки, вы можете использовать:

f(((int[2]){ 1, 2 }));
  ^                ^

Правило, определяющее это поведение, из C99 §6.10.3 / 11, выглядит следующим образом:

Последовательность токенов предварительной обработки, ограниченная наиболее подходящими круглыми скобками. формирует список аргументов для функционально-подобного макроса.

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

1 голос
/ 06 апреля 2011

Если это вообще ошибка, то это со стандартом, а не с gcc (т. Е. В этом отношении я считаю, что gcc делает то, что требует стандарт).

...