Макросы C для более сложных функций

Я видел простые примеры макросов, но мне интересно что-то более сложное, скажем, с операторами if и переназначением заданных переменных. Можно ли сделать более сложные выражения, подобные этому, в макросе? У меня есть функция, которая будет запускаться миллиарды раз, поэтому было бы неплохо, чтобы препроцессор просто добавлял туда код, а не передавал переменные туда и обратно.

Скажем, у меня есть следующая функция:

int foo(int a, int b, int c){  
if (a > 2)  
  c = a;  
if (b > 3)  
  c = b;  

return a + b + c;  
}

Как сделать из этого макрос?


person Jim    schedule 06.02.2011    source источник
comment
ммм. Что именно ты пытаешься сделать? Почему создание этого макроса что-то изменит.   -  person Falmarri    schedule 06.02.2011
comment
В наши дни нет причин использовать макросы для этого - если накладные расходы на вызов значительны, используйте встроенные функции, но макросы не нужны с C89 и имеют множество недостатков и ловушек.   -  person Paul R    schedule 06.02.2011
comment
@Paul: Макросы - это единственный способ универсального программирования на C. Что, если OP нужна функция, подобная той, которая работает с аргументами int, long и double (в любой комбинации)?   -  person R.. GitHub STOP HELPING ICE    schedule 06.02.2011
comment
@R ..: тогда OP должен был упомянуть об этом в вопросе ;-p Насколько я понимаю, this in for this не является общим программированием.   -  person Steve Jessop    schedule 06.02.2011
comment
Я согласен, что макросы здесь бесполезны. Думаю, я пропустил это в комментарии Пола.   -  person R.. GitHub STOP HELPING ICE    schedule 07.02.2011
comment
@R: Хорошее замечание по поводу общего программирования, хотя я бы сказал, что это клуге. ;-)   -  person Paul R    schedule 07.02.2011


Ответы (4)


Обратите внимание, что макросы — это не то же самое, что вызовы функций — макросы фактически заменяют исходный код C, где они используются вместо вызова и возврата — поэтому может быть много неожиданного поведения! Ваш пример можно превратить в такой макрос:

#define FOO(a,b,c)((a)+(b)+(((b)>3)?(b):((a)>2)?(a):(c)))

Но опять же, существует множество ошибок при использовании сложных макросов, например приоритет оператора и дублированные операторы автоинкремента/декремента.

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

person maerics    schedule 06.02.2011
comment
@Alexandre: может быть, вы могли бы опубликовать ответ, объясняющий, почему отвечать на его вопрос так, как он задан, - плохая идея? - person maerics; 06.02.2011
comment
Почему минус? Мне это кажется правильным. Опасно или нет, ответил он на вопрос. - person Dave; 06.02.2011
comment
@maerics: аргументы оцениваются несколько раз (поэтому, если вы передаете x++ вместо a, то x увеличивается 3 раза, и у вас неопределенное поведение), и он не может обнаружить передаваемые неправильные типы параметров, чтобы назвать 2 причины. - person Adam Rosenfield; 06.02.2011
comment
@maerics: существует множество проблем с макросом, который вы определили выше, например, вы даже не заключили скобки вокруг a, b и c, поэтому он потерпит неудачу, если какое-либо из них является выражением. Не говоря уже о побочных эффектах, многократной оценке и т.д. - person Paul R; 06.02.2011
comment
@ Адам, Пол: согласен, обновил ответ, чтобы упомянуть об этом, но, согласно комментарию Дэйва, вопрос в том, как мне сделать эту функцию макросом, нет? - person maerics; 06.02.2011
comment
@Dave: в Интернете есть миллионы злобных часто задаваемых вопросов о макросах, которые сделают это лучше, чем я. Я не люблю изобретать велосипед. - person Alexandre C.; 07.02.2011
comment
Я согласен. Я погуглил, макросы злые, и набрал 12900 просмотров. Но потом я погуглил Просто ответь на вопрос и получил более 4 миллионов. :) А если серьезно, я согласен со всеми вами, что это плохая идея, это был просто резкий минус. - person Dave; 07.02.2011
comment
Согласитесь с @Dave, мы здесь не для того, чтобы баловать людей. Во что бы то ни стало объясните, почему это обычно плохая идея, но не делайте вид, что технически правильного ответа на вопрос не существует. - person caf; 07.02.2011

Легко - не используйте макросы - просто используйте встроенные функции:

__inline int foo(int a, int b, int c)
{  
    if (a > 2)  
        c = a;  
    if (b > 3)  
        c = b;  
    return a + b + c;  
}
person Paul R    schedule 06.02.2011
comment
Или используйте inline вместо __inline, если у вас серьезный компилятор C. Не то чтобы фактическая маркировка функции inline сильно влияет на то, будет ли она встроена приличным компилятором, но тот факт, что определения встроенных функций присутствуют в TU, содержащем вызов. - person Steve Jessop; 06.02.2011
comment
@Steve: действительно, __inline безопаснее и более переносим для кода C, но большинство современных / приличных компиляторов распознают встроенный, хотя для его включения может потребоваться переключатель командной строки. - person Paul R; 06.02.2011
comment
Зависит от того, что вы подразумеваете под портативным. Если данный компилятор не поддерживает inline, то кто знает, какие другие части текущего стандарта C он не поддерживает? Если вы хотите написать код, переносимый обратно в C89, то вы не можете полагаться на какое-либо средство для встроенных функций, и обычно лучше всего определить макрос MY_STATIC_INLINE, который будет определен как static inline в C99, static в чистом C89 и некоторые специфичная для компилятора вещь, включающая __inline, где это возможно. - person Steve Jessop; 06.02.2011
comment
__inline совершенно небезопасно; его использование имеет неопределенное поведение, поскольку имя зарезервировано для реализации. inline безопасно, потому что, если ваш компилятор предшествует C99, вы можете просто #define inline опустить его или #define inline __inline использовать какое-либо ключевое слово __inline, специфичное для компилятора. - person R.. GitHub STOP HELPING ICE; 06.02.2011
comment
@R: inline не совсем безопасен в коде до C99 - вы не можете просто #define удалить его, поскольку в коде с именем inline могут быть существующие функции, переменные и т. д. - person Paul R; 06.02.2011
comment
@ Анонимный голосующий против - пожалуйста, хотя бы объясните, почему вы считаете, что это плохой или бесполезный ответ. - person Paul R; 06.02.2011
comment
@Paul: Вы тот, кто пишет код, поэтому не используйте inline, кроме как в качестве ключевого слова (и исправьте любые такие проблемы в существующем коде; это простой поиск и замена). Это совершенно безопасно, потому что компилятор ничего не испортит. В C ничто не застраховано от того, что некомпетентные программисты все испортят. :-) - person R.. GitHub STOP HELPING ICE; 07.02.2011
comment
@R: не всегда так просто, когда имеешь дело с устаревшим кодом, сторонними библиотеками, что, конечно же, является мотивацией для введения __inline, __asm ​​и др. с префиксами двойного подчеркивания, чтобы избежать конфликтов имен. - person Paul R; 07.02.2011
comment
__inline совсем не переносим. В мире программирования для ПК большинство компиляторов следуют C99, но в большом мире за пределами настольных компьютеров C90 по-прежнему правит, и люди даже намеренно избегают C99. Однако некоторые компиляторы C90 имеют хороший переносимый способ встраивания через #pragma INLINE или аналогичный. Это самый портативный способ в C90. - person Lundin; 07.02.2011
comment
@Lundin: я не уверен насчет ПК и C99 или, по крайней мере, ПК с Windows - Visual Studio до сих пор не поддерживает C99 (хотя поддерживает __inline). Конечно, вы можете безопасно #ifdef отказаться от __inline, если данный компилятор его не поддерживает. - person Paul R; 07.02.2011

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

person Oliver Charlesworth    schedule 06.02.2011

Если похоже, что это должна быть функция, сделайте ее функцией.

Технология компилятора со временем стала достаточно хороша, поэтому вам не нужно беспокоиться о таких вещах. Доверьтесь своему компилятору, и все будет в порядке.

person darioo    schedule 06.02.2011