Я учусь на специальность "Компьютерная инженерия", где у нас есть предмет "Программирования", на котором мы учим язык С++. С программированием, как таковым знаком давно, в арсенале 4 года разработки на Python. С++ когда-то сам начинал учить.. писал простенькие программы, юзал, как язык в игровом движке.. На лабораторной у нас задание, в которое звучит примерно так: "Напишите макрос, который бы сортировал массив", либо "Макрос, который находит сумму чётных элементов массива".. ну и так далее... Пока это делал сто раз проклял автора задания, ибо чем больше когда я пишу, тем больше багов возникает.. Насколько я знаю, макросов вообще стараются по возможности избегать в С++, а если и приходиться использовать, то есть ряд правил, которые необходимо соблюдать для корректной работы. Вопрос, в каких случаях вообще использую макросы, и когда от них стоит отказаться и почему?
А у вас нет ощущения, что методичку по лабораторным писал человек, который просто неверно использует термин "макрос"? По заданиям больше на функцию похоже...
Никита Ярёменко, та щоб тому повылазило, кто настрочил такую хрень, да еще учит ей других.
Никаких реальных причин запихивать такие функции в макросы нет, а вот огрести геморроя от такой практики, наоборот, можно очень легко и непринужденно.
Никита Ярёменко, Но если очень надо, то можно и сделать :-)
Пишите обычную функцию сортировки, так что бы она все возвращала через параметры. Отлаживаете функцию, чтоб она нормально работала. Затем просто подменяете функцию на макрос.
Например, была функция:
void mysort(int *arr, int size)
{
/* тут тело функции */
}
Входной массив arr является и выходным.
Стал макрос:
#define mysort(arr, size) \
do { \
/* тут тело функции */ \
} while(0)
В принципе все.
В do ... while(0) все завернуто по двум причинам:
1. при выходе из цикла все переменные, объявленные внутри цикла уничтожаться и не будут влиять на вызывающий код.
2. при использовании макроса можно ставить в конце точку с запятой, так будет выглядеть совсем как вызов функции
3. Сам цикл компилятор в итоговом коде удалит, но все побочные эффекты останутся
Как уже многие заметили в реальных проектах обычно так не делают, особенно на плюсах. Для подобного есть шаблоны.
На Си еще можно иногда встретить подобный подход, но то же не часто. Например, видел реализацию "встраиваемого" списка и очереди в подобном стиле.
maaGames, Без do while(0) если после макроса ставить точку с запятой, то компилятор выдает предупреждение.
Возможно, это предупреждение появляется при -Wall -Wextra опциях компилятора, не проверял. Я обычно с повышенным уровнем предупреждений собираю, так что у меня предупреждение есть.
maaGames, Согласен.
Но и do while(0) проблему решает без дополнительных манипуляций с опциями.
Кроме того, например, в библиотеках с открытыми исходниками (и не только) часто не известно с какими опциями будет она в итоге собрана.
res2001, единственное преимущество от do-while, что можно сделать break и выйти из "фукнции" досрочно. В принципе, разницы нет, я просто уточнил, что do-while не обязателен.
Макроссы часто используют для условного включения каких-то функций на этапе компиляции. Например, отладочного логирования. Тогда в зависимости от ключей компиляции можно получить релизный исполняемый файл вообще без этого ненужного кода.
Еще макросы можно использовать для гарантирования инлайнинга кода. Если есть что-то часто повторяющееся, например, это же самое логирование, то можно сделать макросы и избегать дополнительных накладных расходов на вызовы функций.
Однако заменять каждый вызов однажды написанной функции sort впихиванием на это место тела всей функции - это даже не стоя в гамаке, а вприпрыжку... Оптимизирующий компилятор уже лет двадцать как делает это, если сочтет нужным, и уж явно не хуже крестовика-джуниора.
При передаче какого-либо выражения в качестве аргумента функции, это выражение сначала приводится к какому-то значению, а значение уже передается функции.
Макросы позволяют не выполнять выражение, а передать его, как есть. Это полезно для создания отложенных функций, так называемых санков (thunk).
Это один из юзкейсов)
Второй юзкейс - упрощение синтаксиса. Или делание его более удобным для применения. Например тебе не удобно пользоваться if выражением. Скажем, постоянно путаешься, какой код выполняется в true блоке, а какой в false.
Берешь и создаешь макрос my-if в котором привычный синтаксис if expression true_clause else_clause превращаешь в допустим if expression then true_clause else false_clause
Что за бред, товарищ! Вы случайно языки программирования не попутали?
С упрощением синтаксиса я еще с натяжкой могу согласиться, хотя никогда не видел такого юзкейса в реальности. Но первый вариант - отборный бред.
макросов вообще стараются по возможности избегать в С++, а если и приходиться использовать, то есть ряд правил, которые необходимо соблюдать для корректной работы. Вопрос, в каких случаях вообще использую макросы, и когда от них стоит отказаться и почему?
Если говорить про ваше задание, то смысла 0, т.к. шаблоны могут успешно их заменить.
Такие вопросы тут уже задавали, поэтому можете почитать