Почему использование скобок в определении макроса дает ошибку? - PullRequest
3 голосов
/ 26 апреля 2019
#define swap(a,b) a = a ^ b; b = a ^ b; a = a ^ b;
int main()
{
    swap(a,b)
}

Дает правильный ответ.

#define swap(a,b) (a = a ^ b; b = a ^ b; a = a ^ b;)
int main()
{
    swap(a,b)
}

Дает ошибку компиляции: «ожидается») «до»;token "

#define swap(a,b) ({a = a ^ b; b = a ^ b; a = a ^ b;})
int main()
{
    swap(a,b); //note the semicolon at the end, without that the compiler gives an error
}

отлично работает.

Теперь моя путаница в том, почему второе не работает?Я думаю, что это должно работать отлично.А во-вторых, зачем мне ставить точку с запятой в конце вызова макроса в третьем?

Ответы [ 2 ]

6 голосов
/ 26 апреля 2019

Если развернуть макрос, три из них будут выглядеть следующим образом:

a = a ^ b; b = a ^ b; a = a ^ b;
(a = a ^ b; b = a ^ b; a = a ^ b;)
({a = a ^ b; b = a ^ b; a = a ^ b;});

Первый - это хорошо.Второе - это синтаксическая ошибка: вы не можете заключить несколько операторов в круглые скобки.Это не вещь.Третий использует расширение GCC, называемое операторными выражениями .Вы можете окружить набор операторов с помощью ({ ... }), чтобы рассматривать его как выражение.

Обратите внимание, что стандартная идиома для наличия нескольких операторов в макросе - это цикл do { ... } while (0) без завершающего полупериода.двоеточие .

#define swap(a,b) do { a = a ^ b; b = a ^ b; a = a ^ b; } while (0)
2 голосов
/ 26 апреля 2019

Препроцессор заменяет определения макросов строкой, а полученный исходный код затем компилируется. Для примера 2 ваш полученный исходный код будет:

int main()
{
    (a = a ^ b; b = a ^ b; a = a ^ b;)
}

и это недействительный код C; вот почему ваш компилятор жалуется. Это также должно ответить на ваш второй вопрос.

Попробуйте с gcc -E mycode.c. -E указывает gcc остановить процесс компиляции после запуска препроцессора.

...