|
Гибкий размер типа данных |
|
|
|
Jul 29 2015, 05:33
|
Гуру
     
Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713

|
Не знаю в какой раздел форума написать, пишу сюда. Хочется иметь тип данных гибкого размера, с размером, зависящим от значения некоего define. Т.е. - например: VAL_X_MAX - максимальное значение, которое может принимать некоторая переменная x. если: 0 <= VAL_X_MAX < 256, то переменная x должна объявиться размером == байт; если: 256 <= VAL_X_MAX < 32768, то переменная x должна объявиться размером == 16 бит; и т.п. Попытался сделать что-то типа: Код #define u8pVOID u8 #define u16pVOID u16 #define u32pVOID u32 #define u64pVOID u64 #define s8pVOID s8 #define s16pVOID s16 #define s32pVOID s32 #define s64pVOID s64 #define flexType_subst3(x) x #define flexType_subst2(x) flexType_subst3(x) #define flexType_subst(prefix, maxVal, suffix, ...) \ flexType_subst2( \ ((maxVal) < B8) ? prefix##8##suffix: \ ((maxVal) < B16) ? prefix##16##suffix: \ ((maxVal) < B32) ? prefix##32##suffix: prefix##64##suffix)) #define flexType(...) flexType_subst(__VA_ARGS__, pVOID) чтобы можно было объявить переменную: static flexType(u, 54) x;где: 54 - макс. значение которое может принимать x Но препроцессор упорно не хочет полностью вычислять выражение и доводить его до u8 останавливается на: static ((54) < 0x00000100) ? u8: ((54) < 0x00010000) ? u16: ((54) < B32) ? u32: u64) x;Интересно - есть-ли какие другие способы? Конечно можно с помощью #if/#else/#endif, но эту конструкцию придётся городить для каждой такой переменной, а хотелось бы 1 раз определить макрос, а потом его использовать, записывая объявления кратко. ЗЫ: Компилятор - IAR for ARM 7.20.
|
|
|
|
|
Jul 29 2015, 07:05
|
Гуру
     
Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713

|
Цитата(scifi @ Jul 29 2015, 11:48)  Что за глупости? Только безумец не знает, что число 54 можно хранить в 8-битной переменной. Зачем для этого хитрый макрос? Блин... Код #define MAX_EVENTS 54 //кол-во обрабатываемых событий static flexType(u, MAX_EVENTS) x; Так понятнее? Чтобы потом, если вдруг потребуется изменить кол-во обрабатываемых событий, не потребовалось лазить по всему коду и менять размер всех переменных, размерность которых зависит от MAX_EVENTS. И конечно имеются массивы типа flexType(u, MAX_EVENTS)
|
|
|
|
|
Jul 29 2015, 07:15
|
Гуру
     
Группа: Свой
Сообщений: 3 020
Регистрация: 7-02-07
Пользователь №: 25 136

|
Цитата(jcxz @ Jul 29 2015, 10:05)  Чтобы потом, если вдруг потребуется изменить кол-во обрабатываемых событий, не потребовалось лазить по всему коду и менять размер всех переменных, размерность которых зависит от MAX_EVENTS. Это всё достигается стандартными средствами. Для того чтобы не требовалось лазить по коду и менять, придуманы макросы и typedefы: Код typedef uint8_t event_type; Если хочется минимальный размер типа, то достаточно добавить assert: Код assert_static(MAX_EVENT < (1UL << (8 * sizeof(event_type)))); // проверить, что размер типа достаточный assert_static(MAX_EVENT >= (1UL << (8 * (sizeof(event_type) / 2)))); // проверить, что размер не избыточный Если сработает assert, то достаточно будет скорректировать код в одном месте (typedef). Ничего страшного, руки не отвалятся.
|
|
|
|
|
Jul 29 2015, 08:05
|
Гуру
     
Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713

|
Цитата(scifi @ Jul 29 2015, 13:15)  Если хочется минимальный размер типа, то достаточно добавить assert: Код assert_static(MAX_EVENT < (1UL << (8 * sizeof(event_type)))); // проверить, что размер типа достаточный assert_static(MAX_EVENT >= (1UL << (8 * (sizeof(event_type) / 2)))); // проверить, что размер не избыточный Если сработает assert, то достаточно будет скорректировать код в одном месте (typedef). Ничего страшного, руки не отвалятся. Ну да, можно так. Но хочется чтобы всё автоматом собиралось само. У меня есть сейчас массив структур, в котором несколько элементов могут хранить некие значения. Максимальное значение для каждого из них задаётся соответствующим define. Все они около 100..200 сейчас. Но завтра возможно придётся один или несколько из них сделать больше. PS: Из реальных вариантов пока вижу только кувалдой в лоб - прописать массив: Код #define FLEX0 u8 #define FLEX1 u8 #define FLEX2 u8 ... #define FLEX255 u8 #define FLEX256 u16 #define FLEX257 u16 ... #define FLEX65535 u16 #define flexType_subst(maxVal) FLEX##maxVal #define flexType(maxVal) flexType_subst(maxVal) На 8 и 16 бит хватит. Если компилятор потянет такое кол-во констант
|
|
|
|
|
Jul 31 2015, 05:46
|
Гуру
     
Группа: Свой
Сообщений: 2 712
Регистрация: 28-11-05
Из: Беларусь, Витебск, Строителей 18-4-220
Пользователь №: 11 521

|
При написании меню мне понадобилось статически менять тип переменной. Для инициализации. Задача не совсем Ваша, но может посмотрите и что-то заимствуете ... Объявление: Код typedef union { int32_t i; float f; } variant_t; Применение Код DigEditing_t dgeFreqRtcCorr = // Меню "Коррекция генератора" { (int32_t const*)&RtcTCorr, // прямое 0, // 0, // неотображать знак 10, 4, // 10 знака, 4 знак после запятой 3, // float {.f = 1952.2}, {.f = 1954.0}, // min,max PRGEDIT, SetRtcFreq, // Редактировать по PRG, сохранять с помощью SetRtcFreq &strMks // "mks" }; И примерно аналогично... ещё пример приведу ... в бутлоадере Правда не я писал Код typedef union { struct { const uint8_t high; const uint8_t low; const VersionDate date; };
struct { volatile uint8_t high_; volatile uint8_t low_; volatile VersionDate date_; };
const uint32_t value; volatile uint32_t value_; } Version;
|
|
|
|
|
Jul 31 2015, 06:45
|
Гуру
     
Группа: Свой
Сообщений: 4 256
Регистрация: 17-02-06
Пользователь №: 14 454

|
А что кстати дает такой тип кроме путаницы и зоопарка дефайнов? в чем разница между Цитата #define MAX_EVENTS 54 //кол-во обрабатываемых событий static flexType(u, MAX_EVENTS) x; и Код typedef int8_t MY_TYPE; static MY_TYPE x; если вопрос в том чтобы не считать сколько нужно для хранения 54, ну можно табличку завести в экселе, например.... ведь если есть MAX_EVENTS, то вы ее ровно в тех местах где она используется ровно нужное число раз напишите, так же как вы напишите MY_TYPE. Меняется в одном месте в начале программы, тайпдефов будет столько сколько уникальных типов, ровно столько сколько у вас было бы дефайновых макс_евантов. В тех местах где вы размер задаете не через дефайн, а явно, можно поставить прямой тип. Ну и опять же если все структуры и все плавает по размерам, съезжают протоколы, ИМХО только путаница.... Цитата При написании меню мне понадобилось статически менять тип переменной. Для инициализации. чет между объявлением и применением я не нашел корреляции %(
|
|
|
|
|
Jul 31 2015, 07:51
|
Гуру
     
Группа: Свой
Сообщений: 2 712
Регистрация: 28-11-05
Из: Беларусь, Витебск, Строителей 18-4-220
Пользователь №: 11 521

|
Цитата(Golikov A. @ Jul 31 2015, 09:45)  чет между объявлением и применением я не нашел корреляции %( Давайте упростим. Объявлен следующий тип: Код typedef union { int32_t i; float f; } variant_t; Далее объявляется следующая переменная Код const variant_t min = {.f = 1952.2}; То есть на этапе инициализации выбирается её тип. Я не проверял что будет, если я объявлю например данную конструкцию typedef union { int8_t i8; int16_t i16; int32_t i32; float f; } variant_t; а при объявлении скажем сделаю const variant_t min = {.i8 = 19}; Сколько будет выделено памяти? Скорее всего будет выделено по максимуму.
|
|
|
|
|
Jul 31 2015, 08:22
|
Гуру
     
Группа: Свой
Сообщений: 4 256
Регистрация: 17-02-06
Пользователь №: 14 454

|
понятно, ну тогда можно и так char AbstractData[8]; *((int *)AbstractData) = 10; *((float *)AbstractData) = 15.43; *((char *)AbstractData) = 'a'; как я понимаю все метания автора не выделить памяти больше чем надо, А то так все можно было лонгами покрыть и всех делов.... кстати вот здесь Цитата const variant_t min = {.i8 = 19}; интересный вопрос что будет если обратиться к ней потом по неправильному полю... такого рода заморочки в структурах надо конечно через void * решать. делать указатель воид, и по какому то признаку правильно к нему обращаться,а юнионы тут излишни ИМХО
|
|
|
|
|
Jul 31 2015, 10:28
|

Гуру
     
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095

|
Цитата(Golikov A. @ Jul 31 2015, 11:22)  понятно, ну тогда можно и так
char AbstractData[8];
*((int *)AbstractData) = 10; *((float *)AbstractData) = 15.43; *((char *)AbstractData) = 'a'; И во-первых огрести все проблемы с выравниванием на отличных от AVR архитектурах, а во-вторых - загадить исходник явными приведениями типов. Тяжелое ассемблерное детство... Цитата(Golikov A. @ Jul 31 2015, 11:22)  такого рода заморочки в структурах надо конечно через void * решать. Почему именно так? Чем это лучше варианта с union (намекаю на выравнивание и загаживание исходников явными приведениями)? А если надо хранить uint64_t, когда указатель на void занимает 32 бита?
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|