jcxz 184 2 марта, 2016 Опубликовано 2 марта, 2016 · Жалоба Вопрос касается не только собственно 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)) в расчёте на ошибку деления на ноль. Но может быть есть более элегантное решение? Что-то в голову больше ничего не приходит...... :( Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
scifi 1 2 марта, 2016 Опубликовано 2 марта, 2016 · Жалоба Хочется сделать внутри макроса, чтобы при подстановке недопустимого значения в качестве аргумента, проект не собирался (компилятор выдавал какую-либо ошибку). Это называется assert_static(). Использую его повсеместно. Его делают и через деление на 0, и другие какие-то способы есть. Не важно, как оно сделано. Важно, что используется аналогично традиционному assert(). Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
novikovfb 17 3 марта, 2016 Опубликовано 3 марта, 2016 · Жалоба если значение известно на этапе препроцессора, то поможет подобная конструкция #if ((MACRO1)>5) || ((MACRO1)<1) #error MACRO1 должен быть от 1 до 4 #endif Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 184 7 марта, 2016 Опубликовано 7 марта, 2016 · Жалоба Это называется 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. если значение известно на этапе препроцессора, то поможет подобная конструкция Прочитайте внимательнее о чём был вопрос. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
kolotoff 0 7 марта, 2016 Опубликовано 7 марта, 2016 · Жалоба В IAR assert_static - undefined :( В IAR, да и в остальных местах, обычно static_assert(value, "message") Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
scifi 1 8 марта, 2016 Опубликовано 8 марта, 2016 · Жалоба В 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 А вообще, при значении аргумента x==true, значение assert_static(x) чему должно быть равно (в разных компиляторах и при собственном определении)? Произвольному значению или определённой константе? Ничему. Как и стандартный assert(), он останавливает компиляцию (обычный - останавливает выполнение программы), если аргумент равен нулю. Вы придумали нечто иное, но похожее. Логично назвать это как-то по-другому, чтобы другие люди не путались. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 184 8 марта, 2016 Опубликовано 8 марта, 2016 · Жалоба Ничему. Как и стандартный assert(), он останавливает компиляцию (обычный - останавливает выполнение программы), если аргумент равен нулю. Вы придумали нечто иное, но похожее. Логично назвать это как-то по-другому, чтобы другие люди не путались. Мне и нужна остановка компиляции. Только чтобы это можно было встроить внутрь выражения, а не отдельной строкой. Таким образом, чтобы при положительном значении assert, это выражение нормально вычислялось-бы и assert не влиял-бы на него. Чтобы его можно было применять внутри всяческих выражений типа #define name(x) f(...), которые можно подставить как внутрь компилируемых строк, так и внутрь #if. Пример я приводил. Тот свой вариант, что я привёл assert_static(), к сожалению в IAR вызывает только варнинг "деление на ноль", а не ошибку. :( Хотя наверно, опциями проекта, можно данных конкретный варнинг перевести в разряд еррор-ов. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
CrimsonPig 0 8 марта, 2016 Опубликовано 8 марта, 2016 · Жалоба Мне и нужна остановка компиляции. Только чтобы это можно было встроить внутрь выражения, а не отдельной строкой. Таким образом, чтобы при положительном значении assert, это выражение нормально вычислялось-бы и assert не влиял-бы на него. Чтобы его можно было применять внутри всяческих выражений типа #define name(x) f(...), которые можно подставить как внутрь компилируемых строк, так и внутрь #if. Тот свой вариант, что я привёл assert_static(), к сожалению в IAR вызывает только варнинг "деление на ноль", а не ошибку. :( Хотя наверно, опциями проекта, можно данных конкретный варнинг перевести в разряд еррор-ов. надеюсь, что ваш компилятор не поддерживает массивов отрицательной длинны :) #define ASSERT_COMPILE(expr) int __static_assert(int static_assert_failed[(expr)?1:-1]) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
amaora 20 8 марта, 2016 Опубликовано 8 марта, 2016 (изменено) · Жалоба Может быть оператор запятая поможет? Или конструкция из скобок ({}), хотя это наверно только в gnu. #define assert_static(e) (1/(e), (e)) Изменено 8 марта, 2016 пользователем amaora Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 184 9 марта, 2016 Опубликовано 9 марта, 2016 · Жалоба надеюсь, что ваш компилятор не поддерживает массивов отрицательной длинны :) #define ASSERT_COMPILE(expr) int __static_assert(int static_assert_failed[(expr)?1:-1]) И как Вы представляете объявление массива внутри выражения???? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
scifi 1 9 марта, 2016 Опубликовано 9 марта, 2016 · Жалоба И как Вы представляете объявление массива внутри выражения???? Можно попробовать схитрить вот так: sizeof(union { char c[(e)?-1:1]; }) Не уверен, что стандарт так разрешает, но в GCC работает. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
CrimsonPig 0 9 марта, 2016 Опубликовано 9 марта, 2016 (изменено) · Жалоба И как Вы представляете объявление массива внутри выражения???? Надо просто прекратить страдать фигней, и жизнь упростится... Для извращенцев: #define MY_MIN(a,B) (((a) < (B)) ? (a) : (B)); ASSERT_COMPILE((a) > 2); int aa = MY_MIN(1, 17); Изменено 9 марта, 2016 пользователем CrimsonPig Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 184 10 марта, 2016 Опубликовано 10 марта, 2016 · Жалоба Надо просто прекратить страдать фигней, и жизнь упростится... По существу есть что сказать? Для извращенцев: #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), ...}; Теперь попробуйте вставить сюда, то, что Вы предложили. Можно попробовать схитрить вот так: sizeof(union { char c[(e)?-1:1]; }) Не уверен, что стандарт так разрешает, но в GCC работает. Да, в принципе можно попробовать. Щас использую вариант с делением на ноль, но деление на ноль вызывает только варнинг компилятора, а не ошибку. Ваш вариант в gcc вызывает именно ошибку? Но всё равно - такой вариант я думаю не получится использовать внутри выражения #if. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
scifi 1 10 марта, 2016 Опубликовано 10 марта, 2016 · Жалоба Но всё равно - такой вариант я думаю не получится использовать внутри выражения #if. Это к чему вообще? Типа "нет в жизни счастья"? Давайте бросим заниматься этим бренным копанием в компиляторах и станем готовиться к вечной жизни. Может быть, хоть там будет хорошо Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
demiurg_spb 0 10 марта, 2016 Опубликовано 10 марта, 2016 · Жалоба Да, в принципе можно попробовать. Щас использую вариант с делением на ноль, но деление на ноль вызывает только варнинг компилятора, а не ошибку. Ваш вариант в gcc вызывает именно ошибку? Это как захочешь, у меня именно так. -Werror - Make all warnings into errors. -Werror= - Make the specified warning into an error. ... Также хочу заметить что в стандарте С11 это уже реализовано "из коробки". тыц Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться