Когда необходимо использовать макросы вместо подставляемых функций?

Я использую синтаксический анализатор из поваренной книги C# 3.0.

Все примеры из этой книги могут быть загружены здесь: http://examples.oreilly.com/9780596516109/

Поиск 'Аргументов' и Вы найдете его. Необходимо сделать некоторые небольшие изменения кода для вытаскивания его из всего этого в собственный класс, но это не большая проблема.

Это поддерживает все Ваши точки кроме последних двух (параметр, объединяющийся & пропавшие без вести пространства).

12
задан Community 23 May 2017 в 12:02
поделиться

8 ответов

В макросах есть пара строго злобных вещей.

Они обрабатывают текст и не имеют области видимости. Если вы #define foo 1 , то любое последующее использование foo в качестве идентификатора не удастся. Это может привести к странным ошибкам компиляции и труднодоступным ошибкам времени выполнения.

Они не принимают аргументы в обычном смысле. Вы можете написать функцию, которая будет принимать два значения int и возвращать максимальное значение, поскольку аргументы будут вычисляться один раз, а значения будут использоваться после этого. Вы не можете написать макрос для этого, потому что он будет оценивать по крайней мере один аргумент дважды и терпеть неудачу с чем-то вроде max (x ++, --y) .

Также есть распространенные ошибки. В них сложно получить сразу несколько утверждений,

7
ответ дан 2 December 2019 в 05:41
поделиться

В большинстве других ответов обсуждается, почему макросы злы, включая то, как в вашем примере есть общий макрос использовать недостаток. Вот пример Страуструпа: http://www.research.att.com/~bs/bs_faq2.html#macro

Но ваш вопрос заключался в том, для чего макросы все еще подходят. Есть некоторые вещи, в которых макросы лучше, чем встроенные функции, и именно здесь вы делаете то, что просто может ' Это может быть сделано с помощью встроенных функций, таких как:

  • вставка токена
  • , имеющая дело с номерами строк или что-то подобное (как для создания сообщений об ошибках в assert () )
  • , имеющих дело с вещами, которые не ' t выражений (например, сколько реализаций offsetof () используют имя типа для создания операции приведения)
  • макрос для получения количества элементов массива (не может сделать это с функцией , поскольку имя массива слишком легко превращается в указатель)
  • создание «полиморфного типа» функционально-подобных вещей в C, где шаблоны недоступны

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

8
ответ дан 2 December 2019 в 05:41
поделиться

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

int x=1;
x = radian2degree(x);
float y=1;
y = radian2degree(y);

проверки типов не будет, и x, y будут содержать другие значения.

Кроме того, следующий код

float x=1, y=2;
float z = radian2degree(x+y);

не будет делать то, что вы думаете, поскольку он будет преобразован в

float z = x+y*0.017453292519;

вместо

float z = (x+y)+0.017453292519;

, что является ожидаемым результатом.

Это всего лишь несколько примеров неправильного поведения и неправильного использования макросов.

Править

вы можете увидеть дополнительные обсуждения этого здесь

7
ответ дан 2 December 2019 в 05:41
поделиться

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

1
ответ дан 2 December 2019 в 05:41
поделиться

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

определения могут быть переопределены до неопределенных, и здесь нет проверки типов.

2
ответ дан 2 December 2019 в 05:41
поделиться

Макросы - зло, потому что вы можете в конечном итоге передать ему больше, чем переменную или скаляр, и это может разрешить нежелательное поведение (определите макрос max для определения max между a и b, но передайте макросу a ++ и b ++ и посмотрим, что произойдет).

0
ответ дан 2 December 2019 в 05:41
поделиться

Если ваша функция все равно будет встроена, разницы в производительности между функцией и макросом нет. Однако есть несколько различий в удобстве использования между функцией и макросом, и все они в пользу использования функции.

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

0
ответ дан 2 December 2019 в 05:41
поделиться

Макросами относительно часто злоупотребляют, и можно легко сделать ошибки, используя их, как показано в вашем примере. Возьмите выражение radian2degree (1 + 1):

  • с макросом он расширится до 1 + 1 * 57.29 ... = 58.29 ...
  • с функцией это будет то, что вы хотите, а именно (1 + 1) * 57.29 ... = ...

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

#define radian2degree(a) ((a) * 57.295779513082)

Но вы должны придерживаться встроенных функций. См. Эти ссылки в C ++ FAQ Lite для получения дополнительных примеров вредоносных макросов и их тонкостей:

2
ответ дан 2 December 2019 в 05:41
поделиться
Другие вопросы по тегам:

Похожие вопросы: