реклама на сайте
подробности

 
 
2 страниц V   1 2 >  
Reply to this topicStart new topic
> Build-time проверка условий
jcxz
сообщение Mar 2 2016, 08:07
Сообщение #1


Гуру
******

Группа: Свой
Сообщений: 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))
в расчёте на ошибку деления на ноль.
Но может быть есть более элегантное решение? Что-то в голову больше ничего не приходит...... sad.gif
Go to the top of the page
 
+Quote Post
scifi
сообщение Mar 2 2016, 10:29
Сообщение #2


Гуру
******

Группа: Свой
Сообщений: 3 020
Регистрация: 7-02-07
Пользователь №: 25 136



Цитата(jcxz @ Mar 2 2016, 11:07) *
Хочется сделать внутри макроса, чтобы при подстановке недопустимого значения в качестве аргумента, проект не собирался (компилятор выдавал какую-либо ошибку).

Это называется assert_static(). Использую его повсеместно. Его делают и через деление на 0, и другие какие-то способы есть. Не важно, как оно сделано. Важно, что используется аналогично традиционному assert().
Go to the top of the page
 
+Quote Post
novikovfb
сообщение Mar 3 2016, 13:11
Сообщение #3


Знающий
****

Группа: Участник
Сообщений: 518
Регистрация: 29-09-11
Пользователь №: 67 450



если значение известно на этапе препроцессора, то поможет подобная конструкция
#if ((MACRO1)>5) || ((MACRO1)<1)
#error MACRO1 должен быть от 1 до 4
#endif
Go to the top of the page
 
+Quote Post
jcxz
сообщение Mar 7 2016, 21:55
Сообщение #4


Гуру
******

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



Цитата(scifi @ Mar 2 2016, 16:29) *
Это называется assert_static(). Использую его повсеместно. Его делают и через деление на 0, и другие какие-то способы есть. Не важно, как оно сделано. Важно, что используется аналогично традиционному assert().

В IAR assert_static - undefined sad.gif
А вообще, при значении аргумента 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) *
если значение известно на этапе препроцессора, то поможет подобная конструкция

Прочитайте внимательнее о чём был вопрос.
Go to the top of the page
 
+Quote Post
Defin
сообщение Mar 7 2016, 23:07
Сообщение #5


Частый гость
**

Группа: Свой
Сообщений: 105
Регистрация: 26-12-11
Из: Казань
Пользователь №: 69 101



Цитата(jcxz @ Mar 8 2016, 00:55) *
В IAR assert_static - undefined sad.gif


В IAR, да и в остальных местах, обычно static_assert(value, "message")
Go to the top of the page
 
+Quote Post
scifi
сообщение Mar 8 2016, 08:12
Сообщение #6


Гуру
******

Группа: Свой
Сообщений: 3 020
Регистрация: 7-02-07
Пользователь №: 25 136



Цитата(jcxz @ Mar 8 2016, 00:55) *
В IAR assert_static - undefined sad.gif

Ну да. Я обычно добавляю к проекту файл 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(), он останавливает компиляцию (обычный - останавливает выполнение программы), если аргумент равен нулю.
Вы придумали нечто иное, но похожее. Логично назвать это как-то по-другому, чтобы другие люди не путались.
Go to the top of the page
 
+Quote Post
jcxz
сообщение Mar 8 2016, 09:09
Сообщение #7


Гуру
******

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



Цитата(scifi @ Mar 8 2016, 14:12) *
Ничему. Как и стандартный assert(), он останавливает компиляцию (обычный - останавливает выполнение программы), если аргумент равен нулю.
Вы придумали нечто иное, но похожее. Логично назвать это как-то по-другому, чтобы другие люди не путались.

Мне и нужна остановка компиляции. Только чтобы это можно было встроить внутрь выражения, а не отдельной строкой. Таким образом, чтобы при положительном значении assert, это выражение нормально вычислялось-бы и assert не влиял-бы на него. Чтобы его можно было применять внутри всяческих выражений типа #define name(x) f(...), которые можно подставить как внутрь компилируемых строк, так и внутрь #if.
Пример я приводил.
Тот свой вариант, что я привёл assert_static(), к сожалению в IAR вызывает только варнинг "деление на ноль", а не ошибку. sad.gif
Хотя наверно, опциями проекта, можно данных конкретный варнинг перевести в разряд еррор-ов.
Go to the top of the page
 
+Quote Post
CrimsonPig
сообщение Mar 8 2016, 16:52
Сообщение #8


Местный
***

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



Цитата(jcxz @ Mar 8 2016, 09:09) *
Мне и нужна остановка компиляции. Только чтобы это можно было встроить внутрь выражения, а не отдельной строкой. Таким образом, чтобы при положительном значении assert, это выражение нормально вычислялось-бы и assert не влиял-бы на него. Чтобы его можно было применять внутри всяческих выражений типа #define name(x) f(...), которые можно подставить как внутрь компилируемых строк, так и внутрь #if.

Тот свой вариант, что я привёл assert_static(), к сожалению в IAR вызывает только варнинг "деление на ноль", а не ошибку. sad.gif
Хотя наверно, опциями проекта, можно данных конкретный варнинг перевести в разряд еррор-ов.


надеюсь, что ваш компилятор не поддерживает массивов отрицательной длинны sm.gif

#define ASSERT_COMPILE(expr) int __static_assert(int static_assert_failed[(expr)?1:-1])
Go to the top of the page
 
+Quote Post
amaora
сообщение Mar 8 2016, 17:07
Сообщение #9


Местный
***

Группа: Участник
Сообщений: 421
Регистрация: 2-01-08
Пользователь №: 33 778



Может быть оператор запятая поможет? Или конструкция из скобок ({}), хотя это наверно только в gnu.

Код
#define assert_static(e)     (1/(e), (e))


Сообщение отредактировал amaora - Mar 8 2016, 17:08
Go to the top of the page
 
+Quote Post
jcxz
сообщение Mar 9 2016, 09:21
Сообщение #10


Гуру
******

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



Цитата(CrimsonPig @ Mar 8 2016, 22:52) *
надеюсь, что ваш компилятор не поддерживает массивов отрицательной длинны sm.gif
#define ASSERT_COMPILE(expr) int __static_assert(int static_assert_failed[(expr)?1:-1])

И как Вы представляете объявление массива внутри выражения????
Go to the top of the page
 
+Quote Post
scifi
сообщение Mar 9 2016, 09:35
Сообщение #11


Гуру
******

Группа: Свой
Сообщений: 3 020
Регистрация: 7-02-07
Пользователь №: 25 136



Цитата(jcxz @ Mar 9 2016, 12:21) *
И как Вы представляете объявление массива внутри выражения????

Можно попробовать схитрить вот так:
Код
sizeof(union { char c[(e)?-1:1]; })

Не уверен, что стандарт так разрешает, но в GCC работает.
Go to the top of the page
 
+Quote Post
CrimsonPig
сообщение Mar 9 2016, 10:37
Сообщение #12


Местный
***

Группа: Участник
Сообщений: 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
Go to the top of the page
 
+Quote Post
jcxz
сообщение Mar 10 2016, 04:13
Сообщение #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.
Go to the top of the page
 
+Quote Post
scifi
сообщение Mar 10 2016, 05:58
Сообщение #14


Гуру
******

Группа: Свой
Сообщений: 3 020
Регистрация: 7-02-07
Пользователь №: 25 136



Цитата(jcxz @ Mar 10 2016, 07:13) *
Но всё равно - такой вариант я думаю не получится использовать внутри выражения #if.

Это к чему вообще? Типа "нет в жизни счастья"? Давайте бросим заниматься этим бренным копанием в компиляторах и станем готовиться к вечной жизни. Может быть, хоть там будет хорошо wacko.gif
Go to the top of the page
 
+Quote Post
demiurg_spb
сообщение Mar 10 2016, 07:38
Сообщение #15


неотягощённый злом
******

Группа: Свой
Сообщений: 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 это уже реализовано "из коробки".
тыц


--------------------
“Будьте внимательны к своим мыслям - они начало поступков” (Лао-Цзы)
Go to the top of the page
 
+Quote Post

2 страниц V   1 2 >
Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 18th July 2025 - 14:27
Рейтинг@Mail.ru


Страница сгенерированна за 0.01508 секунд с 7
ELECTRONIX ©2004-2016