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

Я хотел бы знать то, что недостатки имеют использование препроцессора таким способом:

#define SOME_FUNCTION someFunction(someArgument)

В основном я чувствую, что это неправильно (или конечно не лучшая практика) - но я не уверен, почему... мои навыки препроцессора ржавы в лучшем случае

6
задан Brian Tompsett - 汤莱恩 21 February 2016 в 11:38
поделиться

9 ответов

..

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

5
ответ дан 8 December 2019 в 18:36
поделиться

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

#define MIN(A,B)   ((A) < (B))?(A):(B);

Обратите внимание, что мне нужно обернуть все аргументы в '(' ')', чтобы убедиться, что выражение вычисляется corectly. Но что произойдет, если мы это сделаем?

int  s = MIN(++current,Max);

Кодируя это, я ожидаю, что ток будет увеличен один раз перед вызовом функции. Но так как это макрос, то он инкрементируется один раз в тесте и второй раз, если он все еще меньше Max

.
5
ответ дан 8 December 2019 в 18:36
поделиться

Существует несколько проблем, о которых вы можете подумать:

  • в C ++ MACRO не имеет пространства имен и класса, поэтому оно одинаково везде. Примером для этого являются несчастные мин, а Max определяют где-то в Windows.h. Если вы программируете для Windows и включите Windows.h и хотите написать std :: numeric_limits :: max () Тогда max будет заменен некоторым кодом ... это оставляет некомпьютеруемый код после выполнения препроцессора. (Хорошо, есть способы выключить Min / Max Macros в Windows.h Но это все еще плохой дизайн!)
  • Макрос не может быть отладке. Отладчик остановится на линии, макрос используется не в коде внутри макроса ...
  • Возможная переоценка параметров макроса (вы можете предотвратить это, имея блок с локальными переменными внутри макроса, но это сделало бы отладку Еще хуже!)
2
ответ дан 8 December 2019 в 18:36
поделиться

Хорошо, если вы должны сделать это (и есть некоторые случаи, когда вы можете), то вам следует, по крайней мере, определить макрос как «подобный функциям» таким образом:

#define SOME_FUNCTION() someFunction(defaultArgument)

, в противном случае вы бы написали код, который выглядел как назначение постоянная, когда это было на самом деле функциональный вызов; I.E;

x = SOME_FUNCTION ;  // hidden function call

, но с «функциональным макросом, вы будете обязаны написать:

x = SOME_FUNCTION() ;  // shorthand function-call with default argument

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

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

1
ответ дан 8 December 2019 в 18:36
поделиться

Это иногда полезно в очень замкнутом домене для определения шагов процесса более читаемой моды:

void myfunc() {
  DO_STEP_ONE;
  THEN_ANOTHER_STEP;
  KEEP_GOING;
  LAST_STEP;
}

, но обычно это просто делает код труднее читать и понимать.

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

Я очень редко использую этот вид подхода.

0
ответ дан 8 December 2019 в 18:36
поделиться

, который будет зависеть от языка, компилятора и т. Д., И т. Д. ...

Однако в этом нет ничего плохого, когда имя подразумевает эти директивы ранее процесса компиляция.

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

0
ответ дан 8 December 2019 в 18:36
поделиться

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

-121--4998462-

Я провел дополнительное исследование и обнаружил, что методы equals () и hashcode () также перезаписываются.

Очевидно, что единственной причиной этого может быть добавление javadoc - может быть, поэтому итератор () также был перезаписан.

-121--2402917-

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

Это один из этих дополнительных уровней indirection: -)

Скажем, что в какой-то точку этой функции нужен другой аргумент или ее вообще не нужно вызывать, вы можете изменить # define один раз вместо изменения всех мест, где вызывается функция.

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

0
ответ дан 8 December 2019 в 18:36
поделиться

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

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

0
ответ дан 8 December 2019 в 18:36
поделиться

Недостатком является то, что вы скрываете код. Увеличивается, что вы скрываете код.

Даунс, обычно вытекает вверх.

Обычно этот конкретный подход в значительной степени бесполезно, и если звонок не выглядит больше похоже на

SomeModule-> Somestorage-> функциональный список [Storage.getFableName] .pointer-> ключевой (...).

Нет смысла делать это. Если бы только аргумент - это неясный вызов, сокращение только аргумента. Если это только функция, состязая только функция. Если оба, вам могут быть лучше с

 SOME_FUNCTION(SOME_ARGUMENT);

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

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

0
ответ дан 8 December 2019 в 18:36
поделиться
Другие вопросы по тегам:

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