Недавно увидел любопытную статью: Директива препроцессора define, в которой четко оговаривалась, что define можно использовать не только как замену Константам, но и использовать define в качестве функции: Код (Text): #define R (r) (r + r) Выходит, что можно смело менять во всех местах функции на макрос define? Это ж в несколько раз уменьшит мой код, которого иной раз крайне много. Да и умещать функции в одну строку было бы куда удобнее, для чего и будет нужна define.
Хуже это тем, что можно "зевнуть" скобочку и отгрести в результате презанятнейшие сайд-эффекты, которые даже в интегрированном отладчике не видны. А ещё для того же самого можно после заголовка функции написать "inline" и дать по ж0пе компилятору, чтобы не смел в машинном коде инлайны оформлять как обычные функции. Это будет наиболее праведно.
ertyuo макрос раскрывается каждый раз при написании, следовательно скомпилрованный код не уменьшится, а только вырастет. макросы имеет смысл делать как замену некоторым длинным выражениям, которые неудобно так записывать, плюс куча сайд-эффектов, как заметили. Например, загугли макрос InitializeObjectAttributes. Во всех остальных случаях нужны функции. кстати говоря, пробел между R и (r) не поддерживается. Это будет расценена как замена R на (r) (r + r)
Думаю что InitializeObjectAttributes оправдан исключительно в С, а в С++ макросы допустимы в библиотеках для генерации кода, пока нет variadic templates, плюс может пара мест где нет альтернатив.
Да, лучше инлайн т.к. элегантнее код. Твой метод хорош тем что не будут тратиться ресурсы на прыжок при вызове, а встраиваться функция будет. Но лучше, повторюсь inline. Плохо тем что дизасмить не гуд, и если функция обьёмная то размер будет большой. Нужно использовать если 1 раз вызывается, или время исполнения критически важно.
Инлайн хотя бы легко отладить в сурс-моде, это однозначно определяет то, что код сложнее, чем небольшое выражение арифметическое, стоит писать в инлайнах.
ertyuo Макро-подстановки работают до того, как начинается грамматический разбор происходящего. Например, развертка макроса происходит до того, как начинается двухфазный поиск имен, Koenig lookup, и т.д., что может давать совершенно неожиданные результаты.
достоинство макро - возможность параметрического полиморфизма без слишком большой нагрузки на синтаксис. но в то же время, как отметили выше, подстановка осуществляется на раннем этапе компиляции и подставляемые выражения не будут вычислены на этапе подстановки, а будут тупо вствлены в выражения, что приводит к непиятным эффектам я привык к макро для списков, аттрибутов, оберток типа mzero..
ertyuo Макро - неплохая вещь, но надо соблюдать следующее: 1. Если макро имеет параметры, то нет пробела между именем макро и скобкой. Код (Text): #define R (r) ... // Неправильно #define R(r) ... // Правильно 2. Если макро расширяется в выражение (формулу), то расширение целиком в скобках. Код (Text): #define R(r) r+r // Неправильно #define R(r) (r+r) // Правильно 3. Все параметры в расширении тоже в отдельных скобках. Код (Text): #define R(r) (r+r) // Неправильно #define R(r) ((r)+(r)) // Правильно 4. Точка с запятой в конце не нужна - иначе макро не скомпилируется в сложных выражениях (if ...). Код (Text): #define R(r) ((r)+(r)); // Неправильно #define R(r) ((r)+(r)) // Правильно Ну и конечно надо смотреть за операциями, где параметр может меняться "на месте": ++, --, +=, и т.п. Такое вызовет побочные эффекты, если макро имеет повторение параметра, как (r+r), но и это можно обойти как (2*(r)) например. Кстати, маленькие по размеру функции компилятор автоматически делает inline-ом. Макро делают программу более читаемой и более сопровождаемой. Например, когда надо послать окну сообщение, всегда требуется преобразование типов в WPARAM, LPARAM. Простое макро решает проблему (код писать быстрее и понятнее): Код (Text): #define SEND(h,m,wp,lp) SendMessage (h, m, (WPARAM) (wp), (LPARAM) (lp)); ... SEND (hList, LB_ADDSTRING, 0, "Item #1"); Или, есть статический массив элементов: Код (Text): char* vect_ItemList [] = { "Element #1", "Element #2", "Element #3", "Element #4" }; Размер массива не проставлен, так что можно добавить/удалить в массив (в процессе разработки или поддержки) и код должен автоматически "понимать" размер массива. Простое макро для этого: Код (Text): #define ARRCOUNT(arr) (sizeof (arr) / sizeof (arr [0])) ... for (int item=0; item < ARRCOUNT (vect_ItemList); item++) { ... } Это работает для любых массивов.
Спасибо всем. Про inline просто вообще не был в курсе, видел использование только в программных файлах - conio.h и подобных, но не знал для чего)
#include <stdio.h> #define SIX 1+5 #define NINE 8+1 int main(void) { int value = SIX * NINE; printf("Answer = %d\n", value); return 0; }
кстати, подумал над таким вопросом. вот, например, такой дефайн Код (Text): #define GRADUS_TO_RADIAN(val) ((val) * M_PI / 180.0) или Код (Text): inline double gradus_to_radian(double val) { return val * M_PI / 180.0; } если далее в проге вызывать x = GRADUS_TO_RADIAN(30.0); , то компилятор это наверняка соптимизирует на x = 0.523598775598;. а вот будет ли он оптимизировать инлайн, если я напишу x = gradus_to_radian(30.0); ? имхо, не будет.