макросы и т.п.

Тема в разделе "LANGS.C", создана пользователем GoldFinch, 17 июл 2008.

  1. GoldFinch

    GoldFinch New Member

    Публикаций:
    0
    Регистрация:
    29 мар 2008
    Сообщения:
    1.775
    Разбирая один длинный С-шный исходник, заметил что текст относящийся ко всевозможным проверкам как минимум сопоставим с текстом относящимся к самому алгоритму. Например постоянно встречаются такие конструкции:

    if (0!=var1) {fn(var1);var1=0}
    fn(var1);var1=0

    tempres=fn(...);if (CONST1!=tempres) {...} else debugprint(..."fn"...);
    tempres=fn(...);if (CONST1==tempres) {debugprint(..."fn"...);goto cleanup};
    tempres=fn(...);if (CONST1==tempres) {debugprint(..."fn"...);return ERR};

    r=y(X...);if (CONST1?r) {...} else {dbgprint(...)};
    r=y(X...);if (CONST1==r) dbgprint(...) else if (CONST2==r) dbgprint(...);

    var1=fn(...);ASSERT(var1);
    ASSERT(var1);fn(...,var1,...);

    if (lpfn!=0) lpfn(...);

    и т.д.

    Пока я вижу только два не очень хороших способа от этого избавиться. Первый это переписать все на язык с хорошей поддержкой макросов, например фасм, тогда вызовы будут оформляться например в виде
    [['?']var] '=' ['?']fn '(' ['?']arg1 ',' ... ')' [( '=' | '~' )CONST1] [( '=' | '~' )CONST2] ...
    т.е. "?" перед идентификатором будет генерировать код его проверки, а "опции" после "v=y(x)" будут генерировать код проверки результата. Второй способ - написать дополнительный препроцессор к C. Переписывать пару сотен килобайт кода - удовольствие сомнительное, но и в написание препроцессора дело не то чтобы быстрое.

    Собственно вопрос, есть ли способы получше, а если нет, то существуют ли подобные готовые решения?
     
  2. Com[e]r

    Com[e]r Com[e]r

    Публикаций:
    0
    Регистрация:
    20 апр 2007
    Сообщения:
    2.624
    Адрес:
    ого..
    если тебя не интересует размер генерируемого кода - могу хоть сейчас нарисовать дефайны,
    если интересует - надо чутьчуть подумать и тоже можно нарисовать.

    сам то уже что на дефайнах наработал?
     
  3. Prince

    Prince New Member

    Публикаций:
    0
    Регистрация:
    9 июл 2008
    Сообщения:
    71
  4. GoldFinch

    GoldFinch New Member

    Публикаций:
    0
    Регистрация:
    29 мар 2008
    Сообщения:
    1.775
    как я понимаю на дефайнах впринципе невозможно реализовать какието условия, т.е. например в том же фасме можно сделать макрос HL с синтаксисом
    HL [<var>[<flag>] =] <func>[<flag>] ([ <arg1>[<flag>], <arg2>[<flag>],...])[<flag>]
    где <flag> ::= -z|-nz|-ez|-enz
    который будет заменять конструкции
    "HL var1-z=..." на "if (var1==0) {var1=...}"
    "HL var1-ez=..." на "if (var1==0) ERROR("Error:var1=0");..."
    "...lpfunc1-nz..." на "... if (lpfunc1!=0) {...} ..."
    ...
    "HL func1(...)-enz" на "... tempvar=func1(...); if (tempvar!=0) ERROR("Error:func1 failed");"

    ,а в С такого вроде как сделать нельзя.
     
  5. Com[e]r

    Com[e]r Com[e]r

    Публикаций:
    0
    Регистрация:
    20 апр 2007
    Сообщения:
    2.624
    Адрес:
    ого..
    ну что то вроде
    #define IWISHYOUREDEAD(var,mode,rest) \
    if(!var) if(mode=='z'){var=rest} \
    else if(mode=='e'){ERROR("suck up!");rest}
    ну да, это будет всё кодес, но оптимизатор лишнее вытрет, ибо будет сравнение констант.
    да и удобно ответвления в дефайны отвести так же, чтоб оптимайзеру работы меньше было.

    и что тебе мешает просто сделать #define movnz..; #define movz..; #define movze..; #define mov.......
    ?
     
  6. Com[e]r

    Com[e]r Com[e]r

    Публикаций:
    0
    Регистрация:
    20 апр 2007
    Сообщения:
    2.624
    Адрес:
    ого..
    вобще надо кодес правильный писать, тогда не надо будет думать о макросах =\
     
  7. W4FhLF

    W4FhLF New Member

    Публикаций:
    0
    Регистрация:
    3 дек 2006
    Сообщения:
    1.050
    Во-первых, нафига столько кодеса для отладочного вывода в релизе? А если он в дебаге, то для отладки это норм.

    Во-вторых, и это главное, такой код - плохой тон. Для чего были придуманы исключения, интересно? Вот как раз, чтобы код не расползался на проверках и каждая критичная ошибка была локализована в своей функции, а все функции обрамлены в try-catch блок. Тогда всей этой порнографии в коде быть недолжно.
     
  8. Com[e]r

    Com[e]r Com[e]r

    Публикаций:
    0
    Регистрация:
    20 апр 2007
    Сообщения:
    2.624
    Адрес:
    ого..
    W4FhLF
    вот вот.
     
  9. GoldFinch

    GoldFinch New Member

    Публикаций:
    0
    Регистрация:
    29 мар 2008
    Сообщения:
    1.775
    А при чем тут исключения? Когда функция возвращает ошибку никаких исключений обычно не происходит. Да и вообще, где в коде "if (!x) f(x)" исключение? А даже если и исключение будет, чем try-catch короче if? Кроме того, при "ошибке", надо еще и сообщение сформировать, типа "100: if (!x) f(x) else ERR('100:f(x) call rejected')".

    Насчет кода отладочного вызова в релизе - когда научусь писать релизы без предварительных отладочных версий, выкину все лишние проверки. Только вот например конструкции вида "if (!gSomeGlobalHandle){CloseHandle(gSomeGlobalHandle);gSomeGlobalHandle=NULL};" всеравно никуда не денутся.
     
  10. W4FhLF

    W4FhLF New Member

    Публикаций:
    0
    Регистрация:
    3 дек 2006
    Сообщения:
    1.050
    GoldFinch
    Когда функция возвращает ошибку - это значит в ней что-то пошло не так, как должно было быть при нормальных условиях. Допустим, если f() - функция открытия файла, в x - это путь, то окажись путь невалидным, имеет место быть исключительная ситуация и здесь правильнее не возвращать код ошибки, а бросать исключение.

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

    Сравни:

    Обработка кодов ошибки:

    Код (Text):
    1. bool f(/* parameter list */);
    2. bool g(/* parameter list */);
    3. bool d(/* parameter list */);
    4. bool q(/* parameter list */);
    5.  
    6. ...
    7.  
    8. if(!f(/* parameter list */))
    9. {
    10.   /*
    11.   освобождение ресурсов
    12.   */
    13.  
    14.   return 0;
    15.  
    16. }
    17.  
    18. if(!g(/* parameter list */))
    19. {
    20.   /*
    21.   освобождение ресурсов
    22.   */
    23.  
    24.   return 0;
    25.  
    26. }
    27.  
    28. if(!d(/* parameter list */))
    29. {
    30.   /*
    31.   освобождение ресурсов
    32.   */
    33.  
    34.   return 0;
    35.  
    36. }
    37.  
    38. if(!q(/* parameter list */))
    39. {
    40.   /*
    41.   освобождение ресурсов
    42.   */
    43.  
    44.   return 0;
    45.  
    46. }
    Вариант с исключениями:

    Код (Text):
    1. void f(/* parameter list */);
    2. void g(/* parameter list */);
    3. void d(/* parameter list */);
    4. void q(/* parameter list */);
    5.  
    6. try
    7. {
    8.   f(/* parameter list */);
    9.   g(/* parameter list */);
    10.   d(/* parameter list */);
    11.   q(/* parameter list */);
    12. }
    13. catch(...)
    14. {
    15.   printf("Unknown exception.\n");
    16.   // освобождение ресурсов
    17. }
    18.  
    19. return 0;
    LOL. Сразу весь сорец в консоль выводи, чтобы юзер сам думал где у него там ошибка :)