макрос с аргументами - PullRequest
       2

макрос с аргументами

13 голосов
/ 21 марта 2011

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

#define MIN(x,y) ((x)<(y)?(x):(y))
int x=1,y=2,z;
z=MIN(y,x);

Учитывая, что (а) макрос работает как подстановка текста, (б) фактические аргументы здесь похожи только на формальные аргументыпоменялся местами, - будет ли этот специфический z = MIN (y, x) работать как положено?Если да, то почему?Я имею в виду, как препроцессору удается не путать фактические и формальные аргументы?

Этот вопрос о технических особенностях компилятора C .Это не вопрос C ++.
Этот вопрос никому не рекомендует использовать макросы.
Этот вопрос не о стиле программирования.

Ответы [ 5 ]

15 голосов
/ 21 марта 2011

Внутреннее представление макроса будет примерно таким, где пробелы обозначают границы токенов, а #1 и #2 - магические токены только для внутреннего использования, указывающие, где должны быть заменены параметры:

MIN( #1 , #2 )  -->  ( ( #1 ) < ( #2 ) ? ( #1 ) : ( #2 ) )

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

Что может вызвать проблемы, когда тело макроса использует идентификатор, который isn't формальное имя параметра, но этот идентификатор также появляется в расширении формального параметра.Например, если вы переписали свой макрос MIN с использованием расширений GNU, которые позволяют избежать оценки аргументов дважды ...

#define MIN(x, y) ({ \
    __typeof__(x) a = (x); \
    __typeof__(y) b = (y); \
    a < b ? a : b; \
})

, а затем вы попытались использовать его следующим образом:

int minint(int b, int a) { return MIN(b, a); }

расширение макроса будет выглядеть так:

int minint(int b, int a)
{
   return ({
       __typeof__(b) a = (b);
       __typeof__(a) b = (a);
       a < b ? a : b;
   });
}

, и функция всегда будет возвращать свой первый аргумент, независимо от того, был он меньше.C не может избежать этой проблемы в общем случае, но многие люди предпочитают, чтобы всегда ставили подчеркивание в конце имени каждой локальной переменной, определенной внутри макроса, и Никогда не ставьте подчеркивания на концах любых других идентификаторов.(Сравните поведение гигиенических макросов Схемы , которые гарантированно не имеют этой проблемы. Common Lisp заставляет вас беспокоиться об этом самостоятельно, но, по крайней мере, у вас есть gensym, чтобы помочь.)

4 голосов
/ 21 марта 2011

Будет работать как положено.

#define MIN(x, y) ((x) < (y) ? (x) : (y))
int x=1,y=2,z;
z = MIN(y, x);

становится

int x=1,y=2,z;
z = ((y) < (x) ? (y) : (x));

Имеются ли вышеизложенные синтаксические или семантические ошибки? Нет. Следовательно, результат будет таким, как ожидалось.

2 голосов
/ 21 марта 2011

Так как вы пропускаете закрытие ')', я не думаю, что это будет работать.

Редактировать: Теперь это исправлено, все должно работать нормально.Это не будет путать x и y больше, чем это было бы, если бы у вас была строка x с "x" в ней.

0 голосов
/ 21 марта 2011

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

int x,y,z;
x=1;y=3;
z = min(++x,y);
printf("%d %d %d\n", x,y,z); /* we would expect to get 2 3 2, but we get 3 3 3 . */
0 голосов
/ 21 марта 2011

Во-первых, речь идет не о компиляторе C, а о препроцессоре C.Макрос работает так же, как функция, хотя текстовая подстановка.Какие имена переменных вы используете, не влияют на результат подстановки макроса.Вы могли бы сделать:

#define MIN(x,y) ((x)<(y)?(x):(y))
int blarg=1,bloort=2,z;
z=MIN(bloort,blarg);

и получить тот же результат.

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