Большие C макросы. В чем выгода? - PullRequest
5 голосов
/ 13 июля 2009

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

Некоторые макросы настолько сложны, что мне трудно представить, что кто-то их даже пишет. Я пытался создать один в этом духе, и это был кошмар. Отладка чрезвычайно трудна, так как она занимает N + строк кода в 1 в отладчике (например, где-то в этом большом блоке кода произошла ошибка). Удачи!). Я должен был на самом деле вытащить макрос и запустить его без макроса для его отладки. Единственный способ, которым я мог видеть человека, написавшего это, - это автоматически генерировать его из кода, написанного в функции, после того, как он отладил ее (или быть умнее меня и писать это с первого раза, что, я думаю, всегда возможно) .

Я что-то упустил? Я сумасшедший? Есть ли уловки отладки, о которых я не знаю? Пожалуйста, заполните меня. Я действительно хотел бы услышать от макро-любителей в аудитории. :)

Ответы [ 11 ]

8 голосов
/ 13 июля 2009

Для меня лучшее использование макросов - это сжатие кода и уменьшение количества ошибок. Недостатком, очевидно, является отладка, поэтому их следует использовать с осторожностью.

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

В C ++ многие виды использования, подобные этому, могут быть заменены шаблонами, но не все. Простой пример полезных макросов - макросы обработчиков событий MFC - без них создание таблиц событий было бы намного сложнее, а код, который вам пришлось бы писать (и читать), был бы намного сложнее.

4 голосов
/ 13 июля 2009

Если макросы очень длинные, они, вероятно, делают код коротким, но эффективным. Фактически он мог использовать макросы для явного встраивания кода или удаления точек принятия решения из пути кода времени выполнения.

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

3 голосов
/ 13 июля 2009

Мне известны только две причины делать то, что вы описываете.

Сначала нужно заставить функции быть встроенными. Это в значительной степени бессмысленно, поскольку ключевое слово inline обычно делает то же самое, а встраивание функций в любом случае часто является преждевременной микрооптимизацией.

Во-вторых, имитировать вложенные функции в C или C ++. Это связано с вашими «функциями записи, которые не нужно передавать во всех их параметрах», но на самом деле может быть немного более мощным, чем это. Уолтер Брайт приводит примеров того, как могут быть полезны вложенные функции.

Существуют и другие причины для использования макросов, такие как использование специфических для препроцессора функций (например, включение __FILE__ и __LINE__ в автоматически генерируемые сообщения об ошибках) или сокращение стандартного кода способами, которые не могут выполнять функции и шаблоны ( Boost.Preprocessor библиотека выделяется здесь, см. Boost.ScopeExit или этот пример кода enum для примеров), но эти причины, по-видимому, не подходят для выполнения того, что описать.

3 голосов
/ 13 июля 2009

Для меня макросы - это зло. С их многочисленными побочными эффектами и тем фактом, что в C ++ вы можете получить те же самые преимущества при использовании inline, они не стоят риска.

Например посмотрите этот короткий макрос:

#define max(a, b) ((a)>(b)?(a):(b))

, затем попробуйте этот вызов:

max(i++, j++)

Подробнее. Скажем, у вас есть

#define PLANETS 8
#define SOCCER_MIDDLE_RIGHT 8

если выдается ошибка, она ссылается на '8', но не на любое из ее значимых представлений.

2 голосов
/ 13 июля 2009

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

Для наиболее проблемных макросов я бы рассмотрел запуск кода через препроцессор и замену вывода макроса вызовами функций (по возможности, встроенными) или прямым LOC. Если макросы существуют для совместимости с другими архитектурами / ОС, возможно, вы застряли.

1 голос
/ 20 января 2015

Существует множество веских причин для написания макросов на языке C.

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

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

Я бы сказал, что при отладке сложных макросов (при записи X макросов и т. Д.) Я склонен предварительно обрабатывать исходный файл и заменять предварительно обработанный файл оригиналом.

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

1 голос
/ 13 июля 2009

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

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

0 голосов
/ 20 января 2015

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

Хотя C99 вышел в 1999 году, он долго сопротивлялся; производители коммерческих компиляторов не считают, что внедрение C99 стоит их времени. Некоторые (например, MS) до сих пор не имеют. Поэтому для многих компаний было нереальным практическим решением использовать режим соответствия C99, даже в некоторых случаях для некоторых компиляторов.

Я использовал компиляторы C89, которые имели расширение для встроенных функций, но это расширение было с ошибками (например, множественные ошибки определения, когда их не должно быть), подобные вещи могут отговорить программиста от использования встроенных функций.

Другое дело, что версия макроса эффективно заставляет функцию быть встроенной. Ключевое слово C99 inline является только подсказкой компилятора, и компилятор все еще может решить сгенерировать один экземпляр кода функции, который связан как не встроенная функция. (Один компилятор, который я все еще использую, сделает это, если функция не тривиальна и возвращает void).

0 голосов
/ 04 ноября 2013

Некоторые устаревшие коды, с которыми я работал, очень часто использовали макросы вместо методов. Причина заключалась в том, что у компьютера / ОС / среды выполнения был очень маленький стек, поэтому переполнение стека было распространенной проблемой. Использование макросов вместо методов означало, что в стеке было меньше методов.

К счастью, большая часть этого кода устарела, поэтому его (в основном) больше нет.

0 голосов
/ 15 сентября 2011

Я также работал над продуктом, в котором у старого программиста (которого, к счастью, давно нет) также был особый роман с Макросами. Его «нестандартный» язык сценариев - верх небрежности. Это усугублялось тем фактом, что он писал свои классы C ++ на C, что означало, что все функции класса и переменные были общедоступны. Во всяком случае, он написал почти все в функциях макроса и разнообразных функций (еще одно ужасное чудовище, навязанное миру). Таким образом, вместо того, чтобы писать правильный шаблонный класс, он вместо этого использовал бы макрос! Он также прибегал к макросам, чтобы создавать фабричные классы, а не обычный код ... Его код в значительной степени неуправляем.

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

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

В любом случае, когда вы работаете в унаследованном коде, просто убедитесь, что удаляете немного макросов за раз. Если вы продолжите в том же духе, со временем у вас будет достаточно времени, чтобы удалить их и сделать жизнь немного проще. Я делал это в прошлом, особенно с грязными макросами. Я включаю переключатель компилятора, чтобы препроцессор генерировал выходной файл. Затем я проверяю этот файл, копирую код, делаю отступ и заменяю макрос сгенерированным кодом. Слава Богу за эту функцию компилятора.

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