Зачем скобки нужны для препроцессора, чтобы иметь оператор? - PullRequest
2 голосов
/ 16 февраля 2020

Имея этот код:

#define GREATER(a, b, res) ( \ /* no braces here */
    asm("cmp %1, %2\n\t" \
         "jge 0f\n\t" \
         "movl %1, %0\n\t" \
         "jmp 1f\n" \
         "0:\n\t" \
         "movl %2, %0\n" \
         "1:" \
         : "=r"(res) \
         : "r"(a), "r"(b)); )

Ошибка: c.c:4:2: error: expected expression before ‘asm’ asm("cmp %1, %2\n\t" \

Но эта (только измененные скобки, все остальное осталось - код в противном случае правильный):

#define GREATER(a, b, res) ({ \ /* used braces here - correct */
    asm("cmp %1, %2\n\t" \
         "jge 0f\n\t" \
         "movl %1, %0\n\t" \
         "jmp 1f\n" \
         "0:\n\t" \
         "movl %2, %0\n" \
         "1:" \
         : "=r"(res) \
         : "r"(a), "r"(b)); })

Компилируется без ошибок. Но единственное изменение - это добавление скобок. Так зачем они нужны? Что препроцессор считает оператором? (Если только означает быть в скобках.) Я видел другие макрофункции, объявленные только в скобках (без фигурных скобок), так почему эта должна иметь такие?

Ответы [ 2 ]

6 голосов
/ 16 февраля 2020

Директивы препроцессора не участвуют в этом вопросе. Проблемы:

  • asm(…) - это расширение G CC для языка C. G CC обрабатывает asm, за которым следует ;, как выражение .
  • Круглые скобки являются частями выражений. Когда вы пишете (…), содержимое скобок должно быть выражением. Поскольку asm не является выражением, (asm(…);) является ошибкой.
  • G CC имеет расширение, называемое выражениями оператора , в котором ({…}) имеет значение как выражение, но может содержать операторы. Внутри ({…}) вы можете поместить операторы в фигурные скобки, и G CC будет их оценивать и использовать в них значение последнего выражения выражения 1 в качестве значения ({…}) выражение. (Последнее выражение в ({…}) должно быть выражением-выражением, в отличие от какого-либо другого типа выражения, подобно for l oop.)

Таким образом, ({ asm(…); }) принимается как выражение.

Однако, хотя G CC принимает его, оно нарушает утверждение в документации GCC о том, что «последним в составном выражении должно быть выражение, за которым следует точка с запятой…». Не похоже, что ваш макрос предназначен для использования в качестве выражения; он помещает результат в res, но сам по себе не имеет значения. В этом случае вы можете сделать это просто заявлением, удалив скобки из исходного кода:

#define GREATER(a, b, res) \
    asm("cmp %1, %2\n\t" \
         "jge 0f\n\t" \
         "movl %1, %0\n\t" \
         "jmp 1f\n" \
         "0:\n\t" \
         "movl %2, %0\n" \
         "1:" \
         : "=r"(res) \
         : "r"(a), "r"(b));

Кроме того, люди часто предпочитают опускать окончательный ; в таких макросах, потому что тогда макрос может быть написано как утверждение, когда используется в исходном коде:

GREATER(a, b, res);

вместо того, чтобы выглядеть странным для людей, привыкших к утверждениям, заканчивающимся на ;:

GREATER(a, b, res)

(хотя с ; в определении, вы все равно можете написать GREATER(a, b, res);, но это расширится до ;;, и это может вызвать проблемы, потому что if (foo) GREATER(a, b, res); else… не сможет связать это else с этим if из-за дополнительный ;.)

Сноска

1 A выражение выражение - это выражение, за которым следует ;.

3 голосов
/ 16 февраля 2020

Если вы скомпилируете фрагмент кода как опубликованный, вы действительно получите ошибку, поскольку макрос определен как #define GREATER(a, b, res) ( \ /* no braces here */, а оставшаяся часть фрагмента анализируется как отдельная строка исходного кода, поскольку \ не является последний символ в строке #define.

Вы должны быть осторожны с размещением комментария.

В более общем смысле оператор asm - это не выражение, это утверждение, следовательно, оно не может быть в скобках. Если вы хотите sh использовать макрос в контексте выражения, вы должны преобразовать инструкцию в выражение-выражение , окружив его ({ и }), расширением ag cc, просто как заявление asm. Чтобы результат использовался в контексте выражения, необходимо указать значение:

/* used braces here - correct */
#define GREATER(a, b, res) ({ \
    asm("cmp %1, %2\n\t" \
         "jge 0f\n\t" \
         "movl %1, %0\n\t" \
         "jmp 1f\n" \
         "0:\n\t" \
         "movl %2, %0\n" \
         "1:" \
         : "=r"(res) \
         : "r"(a), "r"(b)); res; })

Наконец, код сборки для вычисления большего из a и b неэффективен. Компилятор, вероятно, сгенерирует лучший код из res = greater(a, b) с greater, определенным как static inline int greater(int a, int b) { return a > b ? a : b; }

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...