|
Build-time проверка условий |
|
|
|
Mar 2 2016, 08:07
|
Гуру
     
Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713

|
Вопрос касается не только собственно IAR, но вообще скорее по языку. Часто сталкиваюсь с необходимостью проверки неких условий внутри макроса на этапе компиляции, при том, что входные аргументы макроса могут быть заданы константами, определёнными не через #define, а через enum. Пример - имеем некий макрос: Код #define m(a) (((a) == 0) ? X: ((a) == 1) ? Y: Z) Допустиммые значения a для него только: 0, 1, 2. Хочется сделать внутри макроса, чтобы при подстановке недопустимого значения в качестве аргумента, проект не собирался (компилятор выдавал какую-либо ошибку). Причём в качестве аргумента могли бы выступать или константы заданные хоть #define-ом хоть enum хоть числовыми константами. Если бы были допустимы только числовые константы, то проблем нет: Код #define CHECK_0 0 #define CHECK_1 1 #define CHECK_2 2 #define concatAB_(a, b) a##b #define concatAB(a, b) concatAB_(a, b) #define m(a) ((concatAB(CHECK_, a) == 0) ? X: (concatAB(CHECK_, a) == 1) ? Y: Z) Для недопустимого аргумента при компиляции будет ошибка "имя CHECK_XXX не определено". Для констант заданных #define тоже подобное решение. Но вот для выражений и констант заданных enum, этот способ не катит. Пока приходится использовать что-то типа такой конструкции: #define m(a) (((a) == 0) ? X: ((a) == 1) ? Y: ((a) == 2) ? Z: 1/((a) >= 0 && (a) < 3)) в расчёте на ошибку деления на ноль. Но может быть есть более элегантное решение? Что-то в голову больше ничего не приходит......
|
|
|
|
|
Mar 7 2016, 21:55
|
Гуру
     
Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713

|
Цитата(scifi @ Mar 2 2016, 16:29)  Это называется assert_static(). Использую его повсеместно. Его делают и через деление на 0, и другие какие-то способы есть. Не важно, как оно сделано. Важно, что используется аналогично традиционному assert(). В IAR assert_static - undefined А вообще, при значении аргумента x==true, значение assert_static(x) чему должно быть равно (в разных компиляторах и при собственном определении)? Произвольному значению или определённой константе? Определил сейчас так: Код #define assert_static(x) ((x) ? 1: 1 / (x)) Использую: Код #define A(x) (((x) >> BitrateTab_PACK) * assert_static((x) == (x) >> BitrateTab_PACK << BitrateTab_PACK)) unsigned char const array[] = {A(...), A(...), A(...), ...}; (build-time-проверка, что все члены массива кратны (1 << BitrateTab_PACK)). Но работает конечно, только если при положительном условии assert_static() возвращает ==1. Цитата(novikovfb @ Mar 3 2016, 19:11)  если значение известно на этапе препроцессора, то поможет подобная конструкция Прочитайте внимательнее о чём был вопрос.
|
|
|
|
|
Mar 7 2016, 23:07
|
Частый гость
 
Группа: Свой
Сообщений: 105
Регистрация: 26-12-11
Из: Казань
Пользователь №: 69 101

|
Цитата(jcxz @ Mar 8 2016, 00:55)  В IAR assert_static - undefined  В IAR, да и в остальных местах, обычно static_assert(value, "message")
|
|
|
|
|
Mar 8 2016, 08:12
|
Гуру
     
Группа: Свой
Сообщений: 3 020
Регистрация: 7-02-07
Пользователь №: 25 136

|
Цитата(jcxz @ Mar 8 2016, 00:55)  В IAR assert_static - undefined  Ну да. Я обычно добавляю к проекту файл assert_static.h: Код #ifndef ASSERT_STATIC_H #define ASSERT_STATIC_H
#define assert_static(e) do { enum { assert_static__ = 1/(e) }; } while (0)
#endif Цитата(jcxz @ Mar 8 2016, 00:55)  А вообще, при значении аргумента x==true, значение assert_static(x) чему должно быть равно (в разных компиляторах и при собственном определении)? Произвольному значению или определённой константе? Ничему. Как и стандартный assert(), он останавливает компиляцию (обычный - останавливает выполнение программы), если аргумент равен нулю. Вы придумали нечто иное, но похожее. Логично назвать это как-то по-другому, чтобы другие люди не путались.
|
|
|
|
|
Mar 8 2016, 09:09
|
Гуру
     
Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713

|
Цитата(scifi @ Mar 8 2016, 14:12)  Ничему. Как и стандартный assert(), он останавливает компиляцию (обычный - останавливает выполнение программы), если аргумент равен нулю. Вы придумали нечто иное, но похожее. Логично назвать это как-то по-другому, чтобы другие люди не путались. Мне и нужна остановка компиляции. Только чтобы это можно было встроить внутрь выражения, а не отдельной строкой. Таким образом, чтобы при положительном значении assert, это выражение нормально вычислялось-бы и assert не влиял-бы на него. Чтобы его можно было применять внутри всяческих выражений типа #define name(x) f(...), которые можно подставить как внутрь компилируемых строк, так и внутрь #if. Пример я приводил. Тот свой вариант, что я привёл assert_static(), к сожалению в IAR вызывает только варнинг "деление на ноль", а не ошибку.  Хотя наверно, опциями проекта, можно данных конкретный варнинг перевести в разряд еррор-ов.
|
|
|
|
|
Mar 8 2016, 16:52
|

Местный
  
Группа: Участник
Сообщений: 329
Регистрация: 23-04-14
Пользователь №: 81 502

|
Цитата(jcxz @ Mar 8 2016, 09:09)  Мне и нужна остановка компиляции. Только чтобы это можно было встроить внутрь выражения, а не отдельной строкой. Таким образом, чтобы при положительном значении assert, это выражение нормально вычислялось-бы и assert не влиял-бы на него. Чтобы его можно было применять внутри всяческих выражений типа #define name(x) f(...), которые можно подставить как внутрь компилируемых строк, так и внутрь #if. Тот свой вариант, что я привёл assert_static(), к сожалению в IAR вызывает только варнинг "деление на ноль", а не ошибку.  Хотя наверно, опциями проекта, можно данных конкретный варнинг перевести в разряд еррор-ов. надеюсь, что ваш компилятор не поддерживает массивов отрицательной длинны  #define ASSERT_COMPILE(expr) int __static_assert(int static_assert_failed[(expr)?1:-1])
|
|
|
|
|
Mar 8 2016, 17:07
|
Местный
  
Группа: Участник
Сообщений: 421
Регистрация: 2-01-08
Пользователь №: 33 778

|
Может быть оператор запятая поможет? Или конструкция из скобок ({}), хотя это наверно только в gnu. Код #define assert_static(e) (1/(e), (e))
Сообщение отредактировал amaora - Mar 8 2016, 17:08
|
|
|
|
|
Mar 9 2016, 09:35
|
Гуру
     
Группа: Свой
Сообщений: 3 020
Регистрация: 7-02-07
Пользователь №: 25 136

|
Цитата(jcxz @ Mar 9 2016, 12:21)  И как Вы представляете объявление массива внутри выражения???? Можно попробовать схитрить вот так: Код sizeof(union { char c[(e)?-1:1]; }) Не уверен, что стандарт так разрешает, но в GCC работает.
|
|
|
|
|
Mar 9 2016, 10:37
|

Местный
  
Группа: Участник
Сообщений: 329
Регистрация: 23-04-14
Пользователь №: 81 502

|
Цитата(jcxz @ Mar 9 2016, 09:21)  И как Вы представляете объявление массива внутри выражения???? Надо просто прекратить страдать фигней, и жизнь упростится... Для извращенцев: Код #define MY_MIN(a,B) (((a) < (B)) ? (a) : (B)); ASSERT_COMPILE((a) > 2);
int aa = MY_MIN(1, 17);
Сообщение отредактировал CrimsonPig - Mar 9 2016, 10:38
|
|
|
|
|
Mar 10 2016, 04:13
|
Гуру
     
Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713

|
Цитата(CrimsonPig @ Mar 9 2016, 16:37)  Надо просто прекратить страдать фигней, и жизнь упростится... По существу есть что сказать? Цитата(CrimsonPig @ Mar 9 2016, 16:37)  Для извращенцев: Код #define MY_MIN(a,B) (((a) < (B)) ? (a) : (B)); ASSERT_COMPILE((a) > 2); int aa = MY_MIN(1, 17); Опять мимо кассы. Сколько раз повторять? Код #define MY_CHECK(x) ... //здесь требуется написать валидный макрос, проверяющий аргумент (x) на соответствие условию нахождения [b]x[/b] в диапазоне [b]Xmin <= x <= Xmax[/b] и вызывающий ошибку (ну хотя-бы варнинг) компиляции в противном случае static char const m[] = {MY_CHECK(X1+Y1), MY_CHECK(X2+Y2), ...}; Теперь попробуйте вставить сюда, то, что Вы предложили. Цитата(scifi @ Mar 9 2016, 15:35)  Можно попробовать схитрить вот так: Код sizeof(union { char c[(e)?-1:1]; }) Не уверен, что стандарт так разрешает, но в GCC работает. Да, в принципе можно попробовать. Щас использую вариант с делением на ноль, но деление на ноль вызывает только варнинг компилятора, а не ошибку. Ваш вариант в gcc вызывает именно ошибку? Но всё равно - такой вариант я думаю не получится использовать внутри выражения #if.
|
|
|
|
|
Mar 10 2016, 07:38
|

неотягощённый злом
     
Группа: Свой
Сообщений: 2 746
Регистрация: 31-01-08
Из: Санкт-Петербург
Пользователь №: 34 643

|
Цитата(jcxz @ Mar 10 2016, 07:13)  Да, в принципе можно попробовать. Щас использую вариант с делением на ноль, но деление на ноль вызывает только варнинг компилятора, а не ошибку. Ваш вариант в gcc вызывает именно ошибку? Это как захочешь, у меня именно так. -Werror - Make all warnings into errors. -Werror= - Make the specified warning into an error. ... Также хочу заметить что в стандарте С11 это уже реализовано "из коробки". тыц
--------------------
“Будьте внимательны к своим мыслям - они начало поступков” (Лао-Цзы)
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|