Лучше отстаивать в C - PullRequest
0 голосов
/ 10 мая 2018

Иногда мне приходится отправлять результат assert через canbus, иногда локальный.Я использую только C, компилятор Embitz с использованием GCC, STM32F407 или STM32F103.Мое настоящее утверждение: .h файл:

extern char *astrbuf;
#define assert(left,operator,right)\
if(!((left) operator (right))) \
 {asprintf(&astrbuf,"\nAssert error %s %d %ld %ld\n",__FILE__, __LINE__,\
  (u32)(left),(u32)(right));\
  asserted();\
 }

.c файл:

void asserted(void)
{ dprint("%s",astrbuf);

, за которым следует код дисплея или код canbus.Пример: assert (millis, <, maxtime);Это работает очень хорошо, но будет лучше, если будет указан оператор.Я просто не вижу, как отобразить или отправить оператору, который может быть <code>==, < или >.

Ответы [ 4 ]

0 голосов
/ 11 мая 2018

Assert - это макрос, насколько я понимаю, он всегда встроенный.Код для машины имеет много утверждений, чтобы предотвратить повреждение, поэтому нужно поддерживать код как можно быстрее, т.е.встроенный в нормальных условиях.Когда что-то идет не так, используется заявленная функция, скорость больше не проблема, безопасность есть.Утвержденная функция отключает двигатели и т. Д. И выдает отчет по шине CAN или локальному дисплею.Я никак не хочу делать все это в макросе.Вот почему часть кода находится в макросе, часть в функции.Пожалуйста, поправьте меня, если мое понимание неверно.Отсутствие глобальной переменной является явным плюсом, и я добавил while (0), как и в других макросах.

0 голосов
/ 10 мая 2018

Почему бы не использовать стандартный интерфейс assert и включить целое выражение?

#define assert(EXPR) \
if (!(EXPR)) \
 {asprintf(&astrbuf, "\nAssert error %s %d %s\n",__FILE__, __LINE__, #EXPR); \
  asserted(); \
 }

... используя оператор строкового макроса #.

Кстати, почему половина вашего кода в макросе, а другая половина в функции asserted? Почему бы не сделать все это в одном месте?

#define assert(EXPR) \
if (!(EXPR)) \
 { \
  asserted(__FILE__, __LINE__, #EXPR); \
 }

с

void asserted(const char *file, int line, const char *expr) {
    char *astrbuf;
    asprintf(&astrbuf, "%s: %d: assertion failed: %s\n", file, line, expr);
    dprint("%s", astrbuf);
    ...
}

Теперь вам больше не нужна глобальная переменная.

Есть еще одна потенциальная проблема. Если вы используете свой макрос следующим образом:

if (foo())
    assert(x > 42);
else
    bar();

... часть else bar(); будет прикреплена к оператору if, скрытому в assert, а не к внешнему if. Чтобы это исправить, вы можете обернуть все это в цикл do while:

#define assert(EXPR) \
    do { \
        if (!(EXPR)) { \
            asserted(__FILE__, __LINE__, #EXPR); \
        } \
    } while (0)

Или, альтернативно, убедитесь, что весь макрос расширяется до одного выражения:

#define assert(EXPR) \
    ((void)((EXPR) || (asserted(__FILE__, __LINE__, #EXPR), 0)))

Конечно, вы также можете поместить условную логику в функцию:

#define assert(EXPR) asserted(!!(EXPR), __FILE__, __LINE__, #expr)
void asserted(int cond, const char *file, int line, const char *expr) {
    if (cond) {
        return;
    }
    ...
}
0 голосов
/ 10 мая 2018

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

Вместо передачи (влево, оператор, вправо) в макрос, попробуйте передать одно логическое условие.Вы можете использовать условие внутри вашей фактической функции assert, а также преобразовать его в строку с помощью макросов.Таким образом, вы все равно можете сообщить обо всем состоянии вашему отладочному модулю (canbus).

Это также будет работать для более сложных выражений, таких как ((ab) <0) </p>

#define assert( condition ) custom_assert( condition , STRINGIFY_CONSTANT( condition ), __FILE__, __LINE__)

Макрос stringify находится в своем собственном заголовочном файле и был получен на основе этой ссылки.https://gcc.gnu.org/onlinedocs/gcc-3.4.3/cpp/Stringification.html

#define STRINGIFY_CONSTANT(a) STRINGIFY_CONSTANT_DO_NOT_USE(a)
#define STRINGIFY_CONSTANT_DO_NOT_USE(a) #a

Очевидно, что не используйте STRINGIFY_CONSTANT_DO_NOT_USE

void custom_assert( int condition , const char * condition_string, const char * file_name, int line_number)
{
    if (!condition)
    {
        dprint("Assert Failed:'%s' File:'%s' Line:'%d'",condition_string, file_name, line_number);
    }
}

Я бы избегал помещать в ваш запрос assert #define что-то большее, чем один вызов функции, поскольку это может быть трудноотладка, и это также увеличит размер вашего кода.Я рекомендую поместить любую логику в функцию.

Я позвонил моему assert custom_assert.У меня также есть много #defines для вывода вывода отладки на разные каналы, такие как usb, rs232, на экран и т. Д. В режиме выпуска утверждения просто перезагружают встроенное устройство, что допустимо в моем приложении.

0 голосов
/ 10 мая 2018

Вы можете использовать оператор строки # для преобразования макропараметра operator в строку #operator:

extern char *astrbuf;
#define assert(left,operator,right)\
if(!((left) operator (right))) \
 {asprintf(&astrbuf,"\nAssert error %s %d %ld %s %ld\n",__FILE__, __LINE__,\
  (u32)(left), #operator, (u32)(right));\
  asserted();\
 }
...