Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Гениальное открытие в синтаксисе языка Си
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > Cредства разработки для МК > IAR
GetSmart
Только что изобрёл, пытаясь сэкономить код smile.gif
Проверил - работает в CW и в IAR.


Код
//#define _DEBUG_LOOP_
#ifdef _DEBUG_LOOP_            /* для установки отладочных ловушек объявить этот символ */
#define DebugLoop(a)    a { DisableIRQ_FIQ(); while (1); }
#else
#define DebugLoop(a)    {}
#endif


int I2CEngine(uInt wrCnt, uInt rdCnt)
{
    long time_out = 100000;        // можно сделать зависимость от wrCnt и rdCnt

    I2CWrLength = wrCnt;
    I2CRdLength = rdCnt;
    I2CRdIndex = 0;
    I2CWrIndex = 0;
    if (I2CStart() == 0)    return I2C_ERROR;

    while (--time_out >= 0)
    {
        if (I2CMasterState >= I2C_SUCCESS)    // дальше I2C_SUCCESS все ошибки
        {
            DebugLoop(if (I2CMasterState != I2C_SUCCESS));            // <<<------------------------- обратите внимание на это
            return I2CMasterState;
        }
    }
    DebugLoop();
    return I2C_TIMEOUT;
}


Если это кто-то уже изобрёл до меня - дайте плиз ссылку. Хотелось бы убедиться smile.gif
Dima_G
#include <assert.h>
assert(...)
GetSmart
Называется открыл Америку smile.gifsmile.gif

Ей богу не знал про assert

_______

Только в моей версии там не совсем параметр. И тем более не типизированный. Там может стоять любая строка сишного кода, в данном случае if (...)
MALLOY2
посмотрите стек LWIP там такое тоже применяется, токо еще и уровни настраиваются в случае отладки, у сибя я тоже такое практикую, токо еще в уарт выбрасываю номер строчки.
_Pasha
Цитата(MALLOY2 @ Sep 28 2009, 10:46) *
токо еще в уарт выбрасываю номер строчки.

+1
И можно еще навернуть выходом из бесконечного цикла по простому приему одного символа
ReAl
Цитата(MALLOY2 @ Sep 28 2009, 10:46) *
токо еще в уарт выбрасываю номер строчки.
А ещё во включённом во все файлы проекта h-файле enum
{ MAIN_C=0, UART_C, MDM_C, и так далее}
и не лениться в начале каждого файла писать
#define THIS_FILE MDM_C
так можно и не только номер строки выбрасывать (под строковое имя файла жалко места, у меня обычно много небольших файлов).

А подстановка любого кода - так это же ниагарский водопад хотя бы и один из вариантов макроса ATOMIC_CODE в отсутствие gcc-шных расширений

Код
#define ATOMIC_CODE(_statements_4_atomic_execution_)    \
do {                            \
    uint8_t _atomic_saved_sreg_ = SREG;     \
    cli();                      \
    { _statements_4_atomic_execution_ }     \
    SREG = _atomic_saved_sreg_;             \
} while(0)

Код
    ATOMIC_CODE(
        ETIMSK &= ~(1 << OCIE3C);
        pf.stop_req = 0;
        stb_off();
    );
Есть свои недостатки, но работает.
Или тут http://electronix.ru/forum/index.php?showt...st&p=268643 - всунутая в макрос структура вроде и не "любой код", но тож ведь "не просто условие".
GetSmart
По поводу do {} while(0) в дефайнах. Кто-нить может объяснить чем это лучше простого {} ???
zltigo
Цитата(GetSmart @ Sep 28 2009, 11:58) *
По поводу do {} while(0) в дефайнах. Кто-нить может объяснить чем это лучше простого {} ???

тем-же, что и (x) лучше простого x
Палыч
Цитата(GetSmart @ Sep 28 2009, 11:58) *
По поводу do {} while(0) в дефайнах. Кто-нить может объяснить чем это лучше простого {} ???
Имхо, тем, что в первом случае "точка с запятой" будет к месту.
Dima_G
Цитата(GetSmart @ Sep 28 2009, 11:58) *
По поводу do {} while(0) в дефайнах. Кто-нить может объяснить чем это лучше простого {} ???


не ручаюсь за терминологию, но как-то так:
do {...} while (0) - выглядит один оператор
{...} - блок операторов

#define FUN do{...} while(0)
#define FUN2 {...}

Код
корректно:
if (..)
  FUN (x);
else
  FUN (2*x);

ошибка:
if (..)
  FUN2 (x);
else
  FUN2 (2*x);




Цитата(GetSmart @ Sep 28 2009, 08:58) *
Только в моей версии там не совсем параметр. И тем более не типизированный. Там может стоять любая строка сишного кода, в данном случае if (...)


Хоть убейте, не могу придумать задачу, где в параметре данного дефайна необходимо поставить что-то окромя булевского выражения laughing.gif
GetSmart
Цитата(Dima_G @ Sep 28 2009, 15:44) *
Хоть убейте, не могу придумать задачу, где в параметре данного дефайна необходимо поставить что-то окромя булевского выражения laughing.gif

Фантазии нету? smile.gif
Например выполнить какие-нить предворительные действия перед зависанием, которые в режиме Release не будут даже компилироваться, а в Debug будут стоять. Как частный случай этого - оператор if
Dima_G
Цитата(GetSmart @ Sep 28 2009, 12:51) *
Фантазии нету? smile.gif
Например выполнить какие-нить предворительные действия перед зависанием, которые в режиме Release не будут даже компилироваться, а в Debug будут стоять. Как частный случай этого - оператор if

Мда?
А можно пример? rolleyes.gif
GetSmart
Цитата(Dima_G @ Sep 28 2009, 15:54) *
Мда?
А можно пример? rolleyes.gif

Код
    DebugLoop(ShowDebugInfo(); if (I2CMasterState != I2C_SUCCESS));

cool.gif

Маленький минус - при какой-либо команде (без завершающего оператора if) внутри скобок придётся ставить точку с запятой.
Dima_G
Цитата(GetSmart @ Sep 28 2009, 14:01) *
Код
    DebugLoop(ShowDebugInfo(); if (I2CMasterState != I2C_SUCCESS));

cool.gif


Код
#define DebugLoop(a)    {}

DebugLoop(ShowDebugInfo(); if (I2CMasterState != I2C_SUCCESS));
развернется в

Код
ShowDebugInfo(); if (I2CMasterState != I2C_SUCCESS){};


Хотя мож я ошибаюсь smile.gif

PS

Согласен smile.gif Ошибаюсь
Палыч
Цитата(GetSmart @ Sep 28 2009, 13:01) *
Код
    DebugLoop(ShowDebugInfo(); if (I2CMasterState != I2C_SUCCESS));
Неудачный пример. Имхо, в Вашем DebugLoop в качестве параметра ничего, кроме if(выражение) и подставить нельзя (разве, что - пусто).
Сергей Борщ
Цитата(GetSmart @ Sep 28 2009, 13:01) *
Код
    DebugLoop(ShowDebugInfo(); if (I2CMasterState != I2C_SUCCESS));
Код
assert(ShowDebugInfo(), I2CMasterState == I2C_SUCCESS);
GetSmart
Цитата(Сергей Борщ @ Sep 28 2009, 17:10) *
Код
assert(ShowDebugInfo(), I2CMasterState == I2C_SUCCESS);

И так допускается использовать assert? Точно так же скомпилится как у меня?
Сергей Борщ
Цитата(GetSmart @ Sep 28 2009, 14:29) *
И так допускается использовать assert? Точно так же скомпилится как у меня?
Не совсем. Скобки забыл.
Код
extern void ShowDebugInfo();
int a;
void test()
{
    assert((ShowDebugInfo(), a == 2));
}


Errors: none
Warnings: none

Done. 0 error(s), 0 warning(s)
GetSmart
Странно. Я в файле assert.h нашёл слишком примитивный дефайн чтобы такой код к нему подошёл. Там сколько параметров внутрь можно уложить? Эти параметры (ну кроме последнего - условия) точно выполняются как код? Не могли бы Вы выложить дефайн ассерта, который такое "вытворяет".
Сергей Борщ
Цитата(GetSmart @ Sep 28 2009, 14:56) *
Не могли бы Вы выложить дефайн ассерта, который такое "вытворяет".
Да любой. Он принимает в качестве параметра выражение, результат которого проверяет на 0. В данном случае я использовал оператор "запятая", объединив в одно выражение и вызов функции и условие, дающее булевый результат.
P.S. Пользуясь случаем: спасибо ReAl, который открыл мне этот интересный оператор своими постами.
Палыч
Цитата(Сергей Борщ @ Sep 28 2009, 14:10) *
Код
assert(ShowDebugInfo(), I2CMasterState == I2C_SUCCESS);
Ну, и кому такое надо?
Процедура ShowDebugInfo() будет вызываться вне зависимости от выполнения условия I2CMasterState == I2C_SUCCESS.

Если уж автору исходного топика так хочется что-то (вызов неких действий) добавлять к его исходному действию по условию, то это делается элементарно. Несколько поправил исходный код:
Код
#define DebugLoop(a)    if(a) { DisableIRQ_FIQ(); while (1); }

Если мы желаем при выполнении условия ещё и процедуру ShowDebugInfo() вызвать, то следует записать
Код
DebugLoop(  (I2CMasterState != I2C_SUCCESS) ? (ShowDebugInfo(), TRUE) : FALSE )

где FALSE и TRUE соответственно ноль и не ноль.
Вот Вам и - пожалуйста: перед заходом в бесконечный цикл получите отладочную информацию.
Нечто подобное можно записать и в assert, однако аргумент его используется не только для проверки условия, но и для формирования строки вывода (не смертельно, конечно, но - некрасиво вывод будет смотреться).

P.S. В assert , конечно, вызов дополнительной процедуры нужно перенести к FALSE.
_Pasha
Цитата(GetSmart @ Sep 28 2009, 11:58) *
По поводу do {} while(0) в дефайнах. Кто-нить может объяснить чем это лучше простого {} ???

Не-не. Лучше for(){} навернуть функционалом. Чтоб можно было не бояться встретить побочные эффекты от break или return при вызове какого-либо хитрого макроса.
Кстати, проблему с обертками для обработчиков (sub lr,lr,#4 ) тоже можно решать с помощью for()
ReAl
Цитата(Палыч @ Sep 28 2009, 17:01) *
Ну, и кому такое надо?
Процедура ShowDebugInfo() будет вызываться вне зависимости от выполнения условия I2CMasterState == I2C_SUCCESS.
...
P.S. В assert , конечно, вызов дополнительной процедуры нужно перенести к FALSE.

Или так
Код
assert( I2CMasterState == I2C_SUCCESS || (ShowDebugInfo(), 0) );
DebugLoop(  I2CMasterState != I2C_SUCCESS  && (ShowDebugInfo(), TRUE) );
Сергей Борщ
Цитата(Палыч @ Sep 28 2009, 17:01) *
Ну, и кому такое надо?
Процедура ShowDebugInfo() будет вызываться вне зависимости от выполнения условия I2CMasterState == I2C_SUCCESS.
GetSmartу. Его макрос делал то же самое. А в остальном вы все правильно расписали.
ReAl
Цитата(_Pasha @ Sep 28 2009, 17:29) *
Не-не. Лучше for(){} навернуть функционалом. Чтоб можно было не бояться встретить побочные эффекты от break или return при вызове какого-либо хитрого макроса.
Дык вроде break одинаково отрабатывает что из того цикла, что из другого. Это по continue в for хвостовой оператор выполнится.

do { } while(0) для другого сделан, чтобы макрос можно было ставить в любое место и привычно писать после него ';', тут уже писали
Код
// примитив, но для общности изложения
#define foo()  op1; op2;

if(a)
    foo(); // в тихую op2 выполняется всегда

if(a)
   foo();
else        // syntax error
   op3;


Код
#define foo()  { op1; op2; }

if(a)
    foo(); // "висящий" ';' , но это не страшно

if(a)
   foo();
else       // syntax error
   op3;

Код
#define foo()  for(int i = 0; i < 1; ++i) { op1; op2; }

if(a)
    foo(); // "висящий" ';' , но это не страшно

if(a)
   foo();
else       // syntax error
   op3;


Код
#define foo()  do { op1; op2; } while(0)

if(a)
    foo(); // OK

if(a)
   foo();
else       // OK
   op3;
_Pasha
Цитата(ReAl @ Sep 28 2009, 18:55) *
Дык вроде break одинаково отрабатывает что из того цикла, что из другого. Это по continue в for хвостовой оператор выполнится.

Это я про ATOMIC_BLOCK() из winavr - там хвостовая часть с атрибутом cleanup и связана с объявленной локальной переменной, поэтому выполнится всегда, даже при break/return.

А так, вообще - про ; подозревал smile.gif
Ну, и использовать break/continue в других случаях - опять же, создавая макроопределениями единый смысловой контекст - тоже неплохо.


Цитата(GetSmart @ Sep 28 2009, 12:51) *
Например выполнить какие-нить предворительные действия перед зависанием, которые в режиме Release не будут даже компилироваться, а в Debug будут стоять. Как частный случай этого - оператор if

Код
#define DEBUGLEVEL 1

#define DEBUG_LOOP(level, assertion) do{if(( level <= DEBUGLEVEL) && (assertion)) for(;;);}while(0)

Я правильно понял? level как константное выр-е, так и динамическим может быть. В последнем случае, конечно, надо позаботиться о значении DEBUGLEVEL, чтобы все отфильтровывалось.
GetSmart
Цитата(Сергей Борщ @ Sep 28 2009, 21:37) *
GetSmartу. Его макрос делал то же самое. А в остальном вы все правильно расписали.

Ну не знал я про assert. Вот, изобрёл велосипед, а люди вокруг запинали творческую личность biggrin.gif Средневековье какое-то.

Знаю, что есть недостаток моего дефайна в том, что он не "ATOMIC", то есть нельзя перед ним написать if (...), хотя условие должно быть внутри (так и было задумано), но иногда из-за этого можно ненароком встать на грабли, если например мой дефайн с процедурой внутри написать сразу после else. Пришлось бы писать примерно так:
Код
if (...)  ++I2CMasterState;
else { DebugLoop(ShowDebugInfo(); if  (I2CMasterState != I2C_SUCCESS)); }
sysel
Ерундой маетесь, товарищи.
Подобные навороты резко снижают читабельность кода.
Вот влезете Вы в свой код годика так через 3 и будете репу чесать у каждой строки, которая Вам сейчас кажется гениальной.
А если кто-то посторонний влезет - вообще труба...
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.