Есть ли мнение о том, является ли использование #define для определения полных строк кода для упрощения кодирования хорошей или плохой практикой программирования? Например, если бы мне нужно было напечатать несколько слов вместе, меня раздражало бы печатать
<< " " <<
Вставить пробел между словами в операторе cout. Я мог бы просто сделать
#define pSpace << " " <<
и введите
cout << word1 pSpace word2 << endl;
Для меня это не добавляет и не вычитает из ясности кода и делает ввод текста немного легче. Есть и другие случаи, когда я могу подумать о том, где печатать будет намного проще, обычно для отладки.
Есть мысли по этому поводу?
РЕДАКТИРОВАТЬ: Спасибо за все отличные ответы! Этот вопрос пришел ко мне после многократного набора текста, но я никогда не думал, что будут другие, менее запутанные макросы. Для тех, кто не хочет читать все ответы, лучшая альтернатива состоит в том, чтобы использовать макросы вашей IDE, чтобы уменьшить количество повторений.
источник
Ответы:
Написание кода легко. Читать код сложно.
Вы пишете код один раз. Он живет годами, люди читают его сто раз.
Оптимизируйте код для чтения, а не для записи.
источник
Лично я ненавижу это. Есть ряд причин, почему я отговариваю людей от этой техники:
Во время компиляции ваши реальные изменения кода могут быть значительными. Следующий парень приходит и даже включает закрывающую скобку в своем #define или вызове функции. То, что написано в определенной точке кода, далеко от того, что будет после предварительной обработки.
Это нечитаемо Это может быть ясно для вас ... пока ... если это только одно определение. Если это станет привычкой, вы скоро получите десятки #defines и начнете терять след. Но, что хуже всего, никто не сможет понять, что
word1 pSpace word2
именно означает (не глядя на #define).Это может стать проблемой для внешних инструментов. Скажем, вы каким-то образом получили #define, который включает закрывающую скобку, но не открывающую скобку. Все может работать хорошо, но редакторы и другие инструменты могут видеть что-то вроде
function(withSomeCoolDefine;
довольно своеобразного (то есть, они сообщат об ошибках и еще много чего). (Подобный пример: вызов функции внутри определения - смогут ли ваши инструменты анализа найти этот вызов?)Обслуживание становится намного сложнее. У вас есть все те, которые определяют в дополнение к обычным проблемам, которые сопровождает обслуживание. В дополнение к вышеупомянутому пункту, поддержка инструментов для рефакторинга также может быть затронута отрицательно.
источник
Моя основная мысль заключается в том, что при написании кода я никогда не использую «упростить типизацию».
Мое основное правило при написании кода - сделать его легко читаемым. Это объясняется тем, что код читается на порядок больше, чем написано. Таким образом, время, которое вы теряете, написав его тщательно, упорядоченно, правильно выложено, фактически потрачено на дальнейшее чтение и понимание намного быстрее.
Таким образом, #define, который вы используете, просто нарушает обычный способ чередования
<<
и прочего . Это нарушает правило наименьшего удивления, и это не ИМХО хорошая вещь.источник
Этот вопрос дает четкий пример того, как вы можете плохо использовать макросы. Чтобы увидеть другие примеры (и развлекаться), посмотрите этот вопрос .
Сказав это, я приведу примеры из реальной жизни того, что я считаю хорошим включением макросов.
Первый пример появляется в CppUnit , который является структурой модульного тестирования. Как и любая другая стандартная среда тестирования, вы создаете тестовый класс, а затем вам необходимо каким-то образом указать, какие методы следует запускать как часть теста.
Как видите, у класса есть блок макросов в качестве первого элемента. Если бы я добавил новый метод
testSubtraction
, очевидно, что вам нужно сделать, чтобы включить его в тестовый прогон.Эти макроблоки расширяются до чего-то вроде этого:
Что бы вы предпочли читать и поддерживать?
Другой пример - инфраструктура Microsoft MFC, где вы отображаете функции на сообщения:
Итак, что же отличает «Хорошие Макросы» от ужасного злого?
Они выполняют задачу, которую нельзя упростить другим способом. Написание макроса для определения максимума между двумя элементами является неправильным, потому что вы можете добиться того же, используя метод шаблона. Но есть некоторые сложные задачи (например, отображение кодов сообщений на функции-члены), которые язык C ++ просто не выполняет элегантно.
Они имеют чрезвычайно строгое формальное использование. В обоих этих примерах макроблоки объявляются с помощью начального и конечного макросов, а промежуточные макросы будут появляться только внутри этих блоков. У вас нормальный C ++, вы на короткое время извиняете себя блоком макросов, а затем снова возвращаетесь в нормальное состояние. В примерах «злых макросов» макросы разбросаны по всему коду, и незадачливый читатель не может узнать, когда применяются правила C ++, а когда - нет.
источник
Во что бы то ни стало, будет лучше, если вы настроите свой любимый IDE / текстовый редактор для вставки фрагментов кода, который вам кажется утомительным повторять снова и снова. А лучше это «вежливый» термин для сравнения. На самом деле, я не могу думать ни о каком подобном случае, когда предварительная обработка бьет макросы редактора. Ну, может быть один - когда по каким-то таинственным и несчастным причинам вы постоянно используете различный набор инструментов для кодирования. Но это не оправдание :)
Это также может быть лучшим решением для более сложных сценариев, когда предварительная обработка текста может сделать вещи намного более нечитаемыми и сложными (подумайте о параметризованном вводе).
источник
<< " " <<
.Другие уже объяснили, почему вы не должны этого делать. Ваш пример, очевидно, не заслуживает реализации с помощью макроса. Но есть широкий спектр случаев, когда у вас есть использовать макросы для удобства чтения.
Известный пример мудрого применения такой техники - проект Clang : посмотрите, как
.def
там используются файлы. С помощью макросов#include
вы можете предоставить одно, иногда полностью декларативное определение для коллекции похожих вещей, которые будут развернуты в объявления типов,case
операторы, где это уместно, инициализаторы по умолчанию и т. Д. Это значительно повышает удобство сопровождения: вы никогда не забудете добавить новыеcase
заявления везде, когда вы добавили новыйenum
, например.Так что, как и с любым другим мощным инструментом, вы должны осторожно использовать препроцессор Си. В искусстве программирования нет общих правил, таких как «вы никогда не должны использовать это» или «вы всегда должны использовать это». Все правила не что иное, как руководящие принципы.
источник
Никогда не стоит так использовать #defines. В вашем случае вы можете сделать это:
источник
Нет.
Для макросов, предназначенных для использования в коде, хорошее руководство для проверки соответствия - заключить его расширение в круглые скобки (для выражений) или фигурные скобки (для кода) и посмотреть, будет ли оно все еще компилироваться:
Макросы, используемые в объявлениях (как пример в ответе Эндрю Шепарда), могут избавиться от более слабого набора правил, если они не нарушают окружающий контекст (например, переключение между
public
иprivate
).источник
Это вполне допустимая вещь в чистой программе на «С».
Это не нужно и запутанно в программе на C ++.
Есть много способов избежать повторяющейся типизации кода в C ++. От использования средств, предоставляемых вашей IDE (даже с vi простое "
%s/ pspace /<< " " <</g
" сэкономит столько же времени при наборе текста и все равно даст стандартный читаемый код). Вы можете определить частные методы для реализации этого или для более сложных случаев шаблон C ++ будет чище и проще.источник
В C ++ это можно решить с помощью перегрузки операторов. Или даже что-то простое, как функция с переменным числом:
lineWithSpaces(word1, word2, word3, ..., wordn)
это просто и экономит ваше печатаниеpSpaces
снова и снова.Так что, хотя в вашем случае это может показаться не таким уж большим делом, есть решение, которое проще и надежнее.
В целом, есть несколько случаев, когда использование макроса значительно короче без введения запутывания, и в основном есть достаточно короткое решение с использованием реальных возможностей языка (макросы - это скорее простая замена строк).
источник
Да, это очень плохо. Я даже видел людей, делающих это:
сохранить набор текста (что вы пытаетесь достичь).
Такой код принадлежит только в таких местах, как это .
источник
Макросы - это зло, и их следует использовать только тогда, когда это действительно необходимо. Есть несколько случаев, когда применимы макросы (в основном отладка). Но в C ++ в большинстве случаев вы можете использовать встроенные функции.
источник
goto
, ко всем возможным макросистемам и т. Д.Нет, вы не можете использовать макросы для сохранения ввода .
Однако вы можете даже использовать их для отделения неизменяемой части кода от изменяющейся и уменьшения избыточности. Для последнего вы должны продумать альтернативы и выбирать макрос только в том случае, если лучшие инструменты не работают. (Для практики макрос находится в конце строки, поэтому наличие последнего означает ...)
Для сокращения набора текста большинство редакторов имеют макросы, даже интеллектуальные фрагменты кода.
источник
switch
/ и т. Д., Вы можете поспорить, что я собираюсь использовать макросы, чтобы избежать сумасшествия и повысить читабельность. Использование макросов для сохранения ввода по ключевым словам, управления потоком данных и т. П. Глупо, но говорить, что никто не может использовать их для сохранения нажатий клавиш в допустимых контекстах, в равной степени глупо.