Я хотел бы знать то, что недостатки имеют использование препроцессора таким способом:
#define SOME_FUNCTION someFunction(someArgument)
В основном я чувствую, что это неправильно (или конечно не лучшая практика) - но я не уверен, почему... мои навыки препроцессора ржавы в лучшем случае
Недостаток? Обычно макроопределение не попадает в таблицу символов исполняемого файла. Немного сложнее отлаживать.
Проблема в том, что каждый раз при использовании аргументов происходит их переоценка:
#define MIN(A,B) ((A) < (B))?(A):(B);
Обратите внимание, что мне нужно обернуть все аргументы в '(' ')', чтобы убедиться, что выражение вычисляется corectly. Но что произойдет, если мы это сделаем?
int s = MIN(++current,Max);
Кодируя это, я ожидаю, что ток будет увеличен один раз перед вызовом функции. Но так как это макрос, то он инкрементируется один раз в тесте и второй раз, если он все еще меньше Max
.Существует несколько проблем, о которых вы можете подумать:
Хорошо, если вы должны сделать это (и есть некоторые случаи, когда вы можете), то вам следует, по крайней мере, определить макрос как «подобный функциям» таким образом:
#define SOME_FUNCTION() someFunction(defaultArgument)
, в противном случае вы бы написали код, который выглядел как назначение постоянная, когда это было на самом деле функциональный вызов; I.E;
x = SOME_FUNCTION ; // hidden function call
, но с «функциональным макросом, вы будете обязаны написать:
x = SOME_FUNCTION() ; // shorthand function-call with default argument
, который лучше соответствует синтаксису предварительно процессора с языком синтаксиса.
Как правило, функциональные макросы лучше всего избежать, но некоторые более коварны, что другие, это ни в коем случае не является худшим случаем. Тем не менее, вы можете так же легко написать функциональную обертку в C, или в C ++ используйте аргумент по умолчанию, и это было бы предпочтительнее в большинстве случаев.
Это иногда полезно в очень замкнутом домене для определения шагов процесса более читаемой моды:
void myfunc() {
DO_STEP_ONE;
THEN_ANOTHER_STEP;
KEEP_GOING;
LAST_STEP;
}
, но обычно это просто делает код труднее читать и понимать.
Если только его не стоимость читателей вашего кода не узнает, что эти те # определяют среднее значение, и это какой-то короткий срез, вы просто получаете людей, чтобы посмотреть в двух местах, чтобы понять линию кода (вершина файл и функция), а не один.
Я очень редко использую этот вид подхода.
, который будет зависеть от языка, компилятора и т. Д., И т. Д. ...
Однако в этом нет ничего плохого, когда имя подразумевает эти директивы ранее процесса компиляция.
Предварительный процессор удаляет все постоянные ссылки по его действительности, все псевдофункциональные с правильным кодом и так далее ...
Возможно, потребуется проверить журнал событий для получения дополнительной информации о фактической основной ошибке
-121--4998462-Я провел дополнительное исследование и обнаружил, что методы equals () и hashcode () также перезаписываются.
Очевидно, что единственной причиной этого может быть добавление javadoc - может быть, поэтому итератор () также был перезаписан.
-121--2402917-Все проблемы в информатике могут решаться другим уровнем indirection
Это один из этих дополнительных уровней indirection: -)
Скажем, что в какой-то точку этой функции нужен другой аргумент или ее вообще не нужно вызывать, вы можете изменить # define
один раз вместо изменения всех мест, где вызывается функция.
Полезно для разработки, но опасно хранить в производственном коде... Я бы запустил препроцессор, чтобы заменить это правило, как только у меня будет зрелый код и я знаю, что мне не нужно будет его менять.
Почему вы ищете недостатки в использовании конкретного препроцессора кода? Использование препроцессорных макросов для чего-либо, кроме условного компиляции (включая включение охранников), должно быть автоматически считаться плохим. Правильный вопрос, чтобы спросить - это ли преимущества для конкретного использования.
Препроцессорные макросы не уважают возможности или использование каким-либо образом. Они могут испортить хороший код в неожиданном и труднодоступном способах. Всегда избегайте их, если у вас нет веских причин использовать один.
Недостатком является то, что вы скрываете код. Увеличивается, что вы скрываете код.
Даунс, обычно вытекает вверх.
Обычно этот конкретный подход в значительной степени бесполезно, и если звонок не выглядит больше похоже на
SomeModule-> Somestorage-> функциональный список [Storage.getFableName] .pointer-> ключевой (...).
Нет смысла делать это. Если бы только аргумент - это неясный вызов, сокращение только аргумента. Если это только функция, состязая только функция. Если оба, вам могут быть лучше с
SOME_FUNCTION(SOME_ARGUMENT);
, если функция никогда не вызывается ни с чем другим, вы можете рассмотреть возможность удаления его из списка аргументов и получения внутри функционального тела. И если пара очень часто повторяется, в небольших вариациях вы можете рассмотреть функции обертки.
После того, как вы сделаете несколько ошибок в коде макроса, вы узнаете о боли, чтобы отладить их, и вы не будете использовать их легкомысленно.