Чем макрос define хуже функций?

Тема в разделе "LANGS.C", создана пользователем ertyuo, 6 янв 2010.

  1. ertyuo

    ertyuo New Member

    Публикаций:
    0
    Регистрация:
    6 янв 2010
    Сообщения:
    2
    Недавно увидел любопытную статью: Директива препроцессора define, в которой четко оговаривалась, что define можно использовать не только как замену Константам, но и использовать define в качестве функции:
    Код (Text):
    1. #define R (r) (r + r)
    Выходит, что можно смело менять во всех местах функции на макрос define? Это ж в несколько раз уменьшит мой код, которого иной раз крайне много. Да и умещать функции в одну строку было бы куда удобнее, для чего и будет нужна define.
     
  2. TermoSINteZ

    TermoSINteZ Синоби даоса Команда форума

    Публикаций:
    2
    Регистрация:
    11 июн 2004
    Сообщения:
    3.552
    Адрес:
    Russia
    Как ты собрался это отлаживать? Особенно когда дефайн большой.
    Подумай. И поймешь, чем же хуже).
     
  3. CyberManiac

    CyberManiac New Member

    Публикаций:
    0
    Регистрация:
    2 сен 2003
    Сообщения:
    2.473
    Адрес:
    Russia
    Хуже это тем, что можно "зевнуть" скобочку и отгрести в результате презанятнейшие сайд-эффекты, которые даже в интегрированном отладчике не видны.

    А ещё для того же самого можно после заголовка функции написать "inline" и дать по ж0пе компилятору, чтобы не смел в машинном коде инлайны оформлять как обычные функции. Это будет наиболее праведно.
     
  4. J0E

    J0E New Member

    Публикаций:
    0
    Регистрация:
    28 июл 2008
    Сообщения:
    621
    Адрес:
    Panama
    Скобочки эт еще ерунда
    Код (Text):
    1. #define R (r) (r + r)
    2.  
    3. int f(int i);
    4.  
    5. ...
    6. int i = 0;
    7. f(R(i++));
     
  5. wasm_test

    wasm_test wasm test user

    Публикаций:
    0
    Регистрация:
    24 ноя 2006
    Сообщения:
    5.582
    ertyuo
    макрос раскрывается каждый раз при написании, следовательно скомпилрованный код не уменьшится, а только вырастет.
    макросы имеет смысл делать как замену некоторым длинным выражениям, которые неудобно так записывать, плюс куча сайд-эффектов, как заметили. Например, загугли макрос InitializeObjectAttributes. Во всех остальных случаях нужны функции.
    кстати говоря, пробел между R и (r) не поддерживается. Это будет расценена как замена R на (r) (r + r)
     
  6. J0E

    J0E New Member

    Публикаций:
    0
    Регистрация:
    28 июл 2008
    Сообщения:
    621
    Адрес:
    Panama
    Думаю что InitializeObjectAttributes оправдан исключительно в С, а в С++ макросы допустимы в библиотеках для генерации кода, пока нет variadic templates, плюс может пара мест где нет альтернатив.
     
  7. reversecode

    reversecode Guest

    Публикаций:
    0
    не макросом лучше менять а инлайн функцией
    литературку по С/C++ почитывайте
     
  8. Yerty

    Yerty New Member

    Публикаций:
    0
    Регистрация:
    6 ноя 2008
    Сообщения:
    107
    Да, лучше инлайн т.к. элегантнее код. Твой метод хорош тем что не будут тратиться ресурсы на прыжок при вызове, а встраиваться функция будет. Но лучше, повторюсь inline. Плохо тем что дизасмить не гуд, и если функция обьёмная то размер будет большой. Нужно использовать если 1 раз вызывается, или время исполнения критически важно.
     
  9. wasm_test

    wasm_test wasm test user

    Публикаций:
    0
    Регистрация:
    24 ноя 2006
    Сообщения:
    5.582
    Инлайн хотя бы легко отладить в сурс-моде, это однозначно определяет то, что код сложнее, чем небольшое выражение арифметическое, стоит писать в инлайнах.
     
  10. _DEN_

    _DEN_ DEN

    Публикаций:
    0
    Регистрация:
    8 окт 2003
    Сообщения:
    5.383
    Адрес:
    Йобастан
    ertyuo

    Макро-подстановки работают до того, как начинается грамматический разбор происходящего. Например, развертка макроса происходит до того, как начинается двухфазный поиск имен, Koenig lookup, и т.д., что может давать совершенно неожиданные результаты.
     
  11. Freeman

    Freeman New Member

    Публикаций:
    0
    Регистрация:
    10 фев 2005
    Сообщения:
    1.385
    Адрес:
    Ukraine
    достоинство макро - возможность параметрического полиморфизма без слишком большой нагрузки на синтаксис. но в то же время, как отметили выше, подстановка осуществляется на раннем этапе компиляции и подставляемые выражения не будут вычислены на этапе подстановки, а будут тупо вствлены в выражения, что приводит к непиятным эффектам :)
    я привык к макро для списков, аттрибутов, оберток типа mzero..
     
  12. AsmGuru62

    AsmGuru62 Member

    Публикаций:
    0
    Регистрация:
    12 сен 2002
    Сообщения:
    689
    Адрес:
    Toronto
    ertyuo
    Макро - неплохая вещь, но надо соблюдать следующее:
    1. Если макро имеет параметры, то нет пробела между именем макро и скобкой.
    Код (Text):
    1. #define R (r)       ...  // Неправильно
    2. #define R(r)        ...  // Правильно
    2. Если макро расширяется в выражение (формулу), то расширение целиком в скобках.
    Код (Text):
    1. #define R(r)        r+r    // Неправильно
    2. #define R(r)        (r+r)  // Правильно
    3. Все параметры в расширении тоже в отдельных скобках.
    Код (Text):
    1. #define R(r)        (r+r)      // Неправильно
    2. #define R(r)        ((r)+(r))  // Правильно
    4. Точка с запятой в конце не нужна - иначе макро не скомпилируется в сложных выражениях (if ...).
    Код (Text):
    1. #define R(r)        ((r)+(r));  // Неправильно
    2. #define R(r)        ((r)+(r))  // Правильно
    Ну и конечно надо смотреть за операциями, где параметр может меняться "на месте": ++, --, +=, и т.п. Такое вызовет побочные эффекты, если макро имеет повторение параметра, как (r+r), но и это можно обойти как (2*(r)) например.

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

    Например, когда надо послать окну сообщение, всегда требуется преобразование типов в WPARAM, LPARAM. Простое макро решает проблему (код писать быстрее и понятнее):
    Код (Text):
    1. #define SEND(h,m,wp,lp)     SendMessage (h, m, (WPARAM) (wp), (LPARAM) (lp));
    2. ...
    3. SEND (hList, LB_ADDSTRING, 0, "Item #1");
    Или, есть статический массив элементов:
    Код (Text):
    1. char* vect_ItemList [] =
    2. {
    3.     "Element #1",
    4.     "Element #2",
    5.     "Element #3",
    6.     "Element #4"
    7. };
    Размер массива не проставлен, так что можно добавить/удалить в массив (в процессе разработки или поддержки) и код должен автоматически "понимать" размер массива. Простое макро для этого:
    Код (Text):
    1. #define ARRCOUNT(arr)       (sizeof (arr) / sizeof (arr [0]))
    2. ...
    3. for (int item=0; item < ARRCOUNT (vect_ItemList); item++)
    4. {
    5.     ...
    6. }
    Это работает для любых массивов.
     
  13. _DEN_

    _DEN_ DEN

    Публикаций:
    0
    Регистрация:
    8 окт 2003
    Сообщения:
    5.383
    Адрес:
    Йобастан
    AsmGuru62

    Так вот ты какой, Капитан Очевидность :)
     
  14. ertyuo

    ertyuo New Member

    Публикаций:
    0
    Регистрация:
    6 янв 2010
    Сообщения:
    2
    Спасибо всем. Про inline просто вообще не был в курсе, видел использование только в программных файлах - conio.h и подобных, но не знал для чего)
     
  15. max7C4

    max7C4 New Member

    Публикаций:
    0
    Регистрация:
    17 мар 2008
    Сообщения:
    1.203
    #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;
    }
     
  16. Aspire

    Aspire New Member

    Публикаций:
    0
    Регистрация:
    19 май 2007
    Сообщения:
    1.028
  17. cupuyc

    cupuyc New Member

    Публикаций:
    0
    Регистрация:
    2 апр 2009
    Сообщения:
    763
    кстати, подумал над таким вопросом. вот, например, такой дефайн
    Код (Text):
    1. #define GRADUS_TO_RADIAN(val) ((val) * M_PI / 180.0)
    или
    Код (Text):
    1. 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); ? имхо, не будет.
     
  18. n0name

    n0name New Member

    Публикаций:
    0
    Регистрация:
    5 июн 2004
    Сообщения:
    4.336
    Адрес:
    Russia
    мб проверить?
    MSVC насколько я помню оптимизирует такие вещи спокойно.
     
  19. cupuyc

    cupuyc New Member

    Публикаций:
    0
    Регистрация:
    2 апр 2009
    Сообщения:
    763
    да, я вместе с виндой всё снёс, так что могу проверить только на CodeBlocks.
     
  20. KeSqueer

    KeSqueer Сергей

    Публикаций:
    0
    Регистрация:
    19 июл 2007
    Сообщения:
    1.183
    Адрес:
    Москва
    cupuyc
    Вроде это обещали только в C++0x