Форум РадиоКот • Просмотр темы - Как разбить двухбайтную переменную на 2 байта в СИ?
Сообщения без ответов | Активные темы
Страница 1 из 2
[ Сообщений: 27 ]
,
Автор
Сообщение
Kalisnik
Заголовок сообщения: Как разбить двухбайтную переменную на 2 байта в СИ?
Добавлено: Пн дек 06, 2021 20:33:43
Зарегистрирован: Вс апр 18, 2021 15:43:55Сообщений: 430
Рейтинг сообщения: 0
Требуется разбить двухбайтную переменную (uint16_t) на старший байт и младший. Как это сделать в СИ?
Вернуться наверх
Реклама
uldemir
Заголовок сообщения: Re: Как разбить двухбайтную переменную на 2 байта в СИ?
Добавлено: Пн дек 06, 2021 20:39:07
Друг Кота
Карма: 50
Рейтинг сообщений: 1398
Зарегистрирован: Пт авг 28, 2009 21:34:30Сообщений: 7321Откуда: 845-й км.
Рейтинг сообщения: 1
Медали: 1
a0 = (ui16 >> 0) & 0x00ff; a1 = (ui16 >> 8) & 0x00ff;
Вернуться наверх
Реклама
DimAlt
Заголовок сообщения: Re: Как разбить двухбайтную переменную на 2 байта в СИ?
Добавлено: Пн дек 06, 2021 21:05:09
Карма: 9
Рейтинг сообщений: 27
Зарегистрирован: Пт май 19, 2006 05:39:11Сообщений: 576
Рейтинг сообщения: 0
Код:
typedef union { uint8_t Byte[2]; uint16_t i; float f; } TValue; TValue Temp; Temp.Byte[0]=0xFF;//uint8_t Temp.Byte[1]=0xFF;//uint8_t Temp.i=0xFFFF//uint16_t Temp.float=1.0;//float
Вернуться наверх
Dimon456
Заголовок сообщения: Re: Как разбить двухбайтную переменную на 2 байта в СИ?
Добавлено: Пн дек 06, 2021 21:10:46
Карма: 20
Рейтинг сообщений: 145
Зарегистрирован: Вс дек 25, 2016 08:34:54Сообщений: 1849
Рейтинг сообщения: 0
Код:
union BytByte { struct { uint8_t l; uint8_t h; } bit; uint16_t byte; }; union BytByte myByte; myByte.byte = 0x1235; a0 = myByte.bit.l; a1 = myByte.bit.h;
Вернуться наверх
Реклама
Eddy_Em
Заголовок сообщения: Re: Как разбить двухбайтную переменную на 2 байта в СИ?
Добавлено: Пн дек 06, 2021 23:30:34
Собутыльник Кота
Карма: -12
Рейтинг сообщений: -24
Зарегистрирован: Пт июл 12, 2019 22:52:01Сообщений: 2516
Рейтинг сообщения: 0
Можно еще проще, т.к. всегда "конечность" архитектуры известра:
Код:
uint16_t data[N]; uint8_t *dptr = (uint8_t*) data; for(int i = 2*N; i > 0; --i) do_something_with(*dptr++);
Если остроконечная, то сначала будет L, потом H; если тупоконечная - наоборот.
Если порядок байт нужно поменять, делаем так:
Код:
uint16_t data[N]; uint8_t *dptr = (uint8_t*) data; for(int i = 0; i < N; ++i){ do_something_with(dptr[1]); do_something_with(dptr[0]); dptr += 2; }
_________________ Linux rules! Windows must die. Здравомыслящий человек добровольно будет пользоваться мастдаем лишь в двух случаях: под дулом автомата или под влиянием анального зонда.Я на гитхабе , в ЖЖ
Вернуться наверх
Реклама
ddr4
Заголовок сообщения: Re: Как разбить двухбайтную переменную на 2 байта в СИ?
Добавлено: Вт дек 07, 2021 01:06:05
Потрогал лапой паяльник
Карма: -14
Рейтинг сообщений: -43
Зарегистрирован: Ср дек 30, 2020 23:05:29Сообщений: 352
Рейтинг сообщения: 0
Код:
uint16_t in_val = 0xBBAA; unsigned char byte_1 = (uint8_t) (in_val & 0x00ff); unsigned char byte_2 = (uint8_t) ((in_val & 0xff00) >> 8); printf("b1: 0x%X, b2: 0x%X\n", byte_1, byte_2);
Код:
Вывод: b1: 0xAA, b2: 0xBB
Вернуться наверх
Реклама
Аlex
Заголовок сообщения: Re: Как разбить двухбайтную переменную на 2 байта в СИ?
Добавлено: Вт дек 07, 2021 10:11:30
Модератор
Карма: 90
Рейтинг сообщений: 1432
Зарегистрирован: Чт мар 18, 2010 23:09:57Сообщений: 4594Откуда: Планета Земля
Рейтинг сообщения: 1
Медали: 1
Код:
uint16_t in_val = 0xBBAA; unsigned char byte_1 = (uint8_t) (in_val & 0x00ff); unsigned char byte_2 = (uint8_t) ((in_val & 0xff00) >> 8); printf("b1: 0x%X, b2: 0x%X\n", byte_1, byte_2);
Зачем "& 0x00ff" и "& 0xff00" ?
В первом случае, при присвоении к 8-ми битной переменной, старший байт сам улетит.
Во втором случае, он улетит при сдвиге вправо.
Лишние букафки в исходнике.
Добавлено after 8 minutes 21 second: Код:
uint16_t uint16_val = 0x0123; uint8_t v1 = uint16_val; uint8_t v2 = uint16_val >> 8;
Вернуться наверх
Dimon456
Заголовок сообщения: Re: Как разбить двухбайтную переменную на 2 байта в СИ?
Добавлено: Вт дек 07, 2021 14:09:34
Карма: 20
Рейтинг сообщений: 145
Зарегистрирован: Вс дек 25, 2016 08:34:54Сообщений: 1849
Рейтинг сообщения: 0
И конечно эффективность кода
Спойлер do_something_withЦитата:
warning: implicit declaration of function 'do_something_with' [-Wimplicit-function-declaration]
функция из с++, очень бы хотелось глянуть на выхлоп с++, плиз, если вас не затруднитДобавлено after 3 hours 54 minutes 29 seconds: Что-то все так промолчали?
Давайте усложним, выдернем не только байты, но и полубайты, и что характерно одной конструкцией
Спойлер Код:
union BytByte { struct { uint8_t l; uint8_t h; } bit; struct { unsigned m:4; unsigned l:4; unsigned h:4; unsigned g:4; } tet; uint16_t byte; };
Вернуться наверх
DX168B
Заголовок сообщения: Re: Как разбить двухбайтную переменную на 2 байта в СИ?
Добавлено: Вт дек 07, 2021 14:49:53
Друг Кота
Карма: 25
Рейтинг сообщений: 99
Зарегистрирован: Вс янв 24, 2010 19:19:52Сообщений: 4468Откуда: Главный Улей России (Moscow)
Рейтинг сообщения: 1
В последнем проекте у меня много вот такого "ужаса", потому что оперативку и EEPROM нужно было экономить. Особенно EEPROM.
Спойлер Код:
typedef struct COutsCfg { union { struct { uint16_t out_0_cfg : 2 ; uint16_t out_1_cfg : 2 ; uint16_t out_2_cfg : 2 ; uint16_t out_3_cfg : 2 ; uint16_t out_4_cfg : 2 ; uint16_t out_5_cfg : 2 ; uint16_t out_6_cfg : 2 ; uint16_t out_7_cfg : 2 ; }; uint16_t config16 ; }; uint8_t beforeResetTimeout ; uint8_t resetTimeout ; uint8_t afterResetTimeout ; } OutsCfg ;
Битовые поля в union.
Короче, есть два варианта:
Код:
uint16_t foo = 0xAA55 ; uint8_t low = foo & 0x00FF ; uint8_t high = ( foo & 0xFF00 ) >> 8 ;
Код:
typedef union _FooType { struct { uint8_t low ; uint8_t high ; }; uint16_t foo ; } FooType ; FooType foo ; foo . foo = 0xAA55 ;
Суть второго варианта в том, что структура упакует свои поля в одно 16-битное слово, которое уже отражается в поле foo объединения FooType.
_________________ I am DX168B and this is my favourite forum on internet!
Вернуться наверх
Реклама
ddr4
Заголовок сообщения: Re: Как разбить двухбайтную переменную на 2 байта в СИ?
Добавлено: Вт дек 07, 2021 15:01:14
Потрогал лапой паяльник
Карма: -14
Рейтинг сообщений: -43
Зарегистрирован: Ср дек 30, 2020 23:05:29Сообщений: 352
Рейтинг сообщения: 0
Код:
uint16_t in_val = 0xBBAA; unsigned char byte_1 = (uint8_t) (in_val & 0x00ff); unsigned char byte_2 = (uint8_t) ((in_val & 0xff00) >> 8); printf("b1: 0x%X, b2: 0x%X\n", byte_1, byte_2);
Зачем "& 0x00ff" и "& 0xff00" ?
В первом случае, при присвоении к 8-ми битной переменной, старший байт сам улетит.
Во втором случае, он улетит при сдвиге вправо.
Лишние букафки в исходнике.
Добавлено after 8 minutes 21 second: Код:
uint16_t uint16_val = 0x0123; uint8_t v1 = uint16_val; uint8_t v2 = uint16_val >> 8;
"0xff00" в образовательных целях, да это пример аналогичный
Код:
uint8_t v1 = ( uint8_t ) uint16_val ; uint8_t v2 = ( uint8_t ) ( uint16_val >> 8 );
Причём машинный код генерируется (gcc) идентичный.
ПС. Код (усечение + битовый сдвиг) на одну (union) или две (struct *) машинных команд меньше. (без оптимизации)
Код:
typedef union { struct { uint8_t b1 ; uint8_t b2 ; }; uint16_t dwaBytes ; } DwaBytes_t ; DwaBytes_t dwaByte = { . dwaBytes = 0xBBAA };
Вернуться наверх
Kalisnik
Заголовок сообщения: Re: Как разбить двухбайтную переменную на 2 байта в СИ?
Добавлено: Вт дек 07, 2021 20:29:07
Зарегистрирован: Вс апр 18, 2021 15:43:55Сообщений: 430
Рейтинг сообщения: 0
А что будет если от переменной unsigned равной нулю, отнять какое-то число? Например, 25? Unsigned переменная ведь не может иметь знака -... В онлайн симуляторе СИ биты инвертируются и переменная приобретает неприлично большое значение. В CVAVR будет такое же поведение?
Вернуться наверх
Dimon456
Заголовок сообщения: Re: Как разбить двухбайтную переменную на 2 байта в СИ?
Добавлено: Вт дек 07, 2021 20:48:54
Карма: 20
Рейтинг сообщений: 145
Зарегистрирован: Вс дек 25, 2016 08:34:54Сообщений: 1849
Рейтинг сообщения: 0
Вы как-то все радикально к этому по дошли, давайте что нибудь по проще, к примеру так
Код:
uint16_t temp; uint8_t data[2]; // туда temp = *((uint16_t*)&data[0]); // обратно *((uint16_t*)&data[0]) = temp;
Вернуться наверх
Eddy_Em
Заголовок сообщения: Re: Как разбить двухбайтную переменную на 2 байта в СИ?
Добавлено: Вт дек 07, 2021 21:44:18
Собутыльник Кота
Карма: -12
Рейтинг сообщений: -24
Зарегистрирован: Пт июл 12, 2019 22:52:01Сообщений: 2516
Рейтинг сообщения: 0
Dimon456 , зачем ты завел две переменные для одних и тех же данных? Вот так же:
Код:
uint16_t temp; uint8_t *data = (uint8_t*) &temp; data[0] = 0xad; data[1] = 0xde; printf("16bit: 0x%x\n", temp); // Little-endian 8 -> 16bit temp = 0xaabb; printf("lo: 0x%s, hi: 0x%x\n", data[0], data[1]); // 16bit -> little-endian 8
_________________ Linux rules! Windows must die. Здравомыслящий человек добровольно будет пользоваться мастдаем лишь в двух случаях: под дулом автомата или под влиянием анального зонда.Я на гитхабе , в ЖЖ
Вернуться наверх
Kalisnik
Заголовок сообщения: Re: Как разбить двухбайтную переменную на 2 байта в СИ?
Добавлено: Вт дек 07, 2021 22:17:52
Зарегистрирован: Вс апр 18, 2021 15:43:55Сообщений: 430
Рейтинг сообщения: 0
DX168B , структуры не требовательны к ресурсам? AVR'у будет не тяжело?
Вернуться наверх
GoldenAndy
Заголовок сообщения: Re: Как разбить двухбайтную переменную на 2 байта в СИ?
Добавлено: Вт дек 07, 2021 23:39:52
Поставщик валерьянки для Кота
Карма: 66
Рейтинг сообщений: 536
Зарегистрирован: Чт июл 28, 2016 07:58:37Сообщений: 1925Откуда: Kyiv, UA
Рейтинг сообщения: 5
А что будет если от переменной unsigned равной нулю, отнять какое-то число? Например, 25? Unsigned переменная ведь не может иметь знака -...
Си не контролирует выходы за пределы диапазона.
И все переполнения и прочее - на совести программиста.
Пусть будет unsigned char n = 0
тогда
n -= 25;
приведет к тому, что из 0 вычтется 25.
Результат будет -25.
-25 в знаковом представлении записывается как 0xE7.
Этот результат и запишется в нашу переменную n.
Но поскольку она беззнаковая - значение будет интерпретироваться как 231.
Вас же не удивит факт, если к байтовой переменной, в которой записано 240 (0xF0) прибавить 20 (0x14), то получится не 260, а 4 (0x04) ?
0xF0 + 0x14 = 0x104. Но 1 теряется, ибо переменная байтовая. Остается 0x04.
То же самое при вычитании работает.
_________________ Telegram Лучшая благодарность -> [+]
Вернуться наверх
DX168B
Заголовок сообщения: Re: Как разбить двухбайтную переменную на 2 байта в СИ?
Добавлено: Ср дек 08, 2021 09:14:00
Друг Кота
Карма: 25
Рейтинг сообщений: 99
Зарегистрирован: Вс янв 24, 2010 19:19:52Сообщений: 4468Откуда: Главный Улей России (Moscow)
Рейтинг сообщения: 1
DX168B , структуры не требовательны к ресурсам? AVR'у будет не тяжело?
Нет. В Си структуры превращаются в обычные массивы. Структуры с битовыми полями у меня не потребляли больше обычных операций с масками и сдвигами.
Пример из реального проекта:
Код:
typedef struct COutsCfg { union { struct { uint16_t out_0_cfg : 2 ; uint16_t out_1_cfg : 2 ; uint16_t out_2_cfg : 2 ; uint16_t out_3_cfg : 2 ; uint16_t out_4_cfg : 2 ; uint16_t out_5_cfg : 2 ; uint16_t out_6_cfg : 2 ; uint16_t out_7_cfg : 2 ; }; uint16_t config16 ; }; uint8_t beforeResetTimeout ; uint8_t resetTimeout ; uint8_t afterResetTimeout ; } OutsCfg ; OutsCfg outCfg ; outCfg . config16 = OUTPUTS_DEFAULT_CONFIG ; outCfg . beforeResetTimeout = OUTPUTS_TIMEOUT_BEFORE_RESET ; outCfg . resetTimeout = OUTPUTS_TIMEOUT_RESET ; outCfg . afterResetTimeout = OUTPUTS_TIMEOUT_AFTER_RESET ; eeprom_write_block (& outCfg , ( void *)( CONFIG_OUTS_OFFSET ), sizeof ( OutsCfg )); OutsCfg outCfg ; outCfg . config16 = OUTPUTS_DEFAULT_CONFIG ; 35d4 : 8a ea ldi r24 , 0xAA ; 170 35d6 : 9a e0 ldi r25 , 0x0A ; 10 35d8 : 9a 83 std Y + 2 , r25 ; 0x02 35da : 89 83 std Y + 1 , r24 ; 0x01 E :\ PlatformIO \ DailyTimer / src / Config . cpp : 38 outCfg . beforeResetTimeout = OUTPUTS_TIMEOUT_BEFORE_RESET ; 35dc : 8e e1 ldi r24 , 0x1E ; 30 35de : 8b 83 std Y + 3 , r24 ; 0x03 E :\ PlatformIO \ DailyTimer / src / Config . cpp : 39 outCfg . resetTimeout = OUTPUTS_TIMEOUT_RESET ; 35e0 : 12 e0 ldi r17 , 0x02 ; 2 35e2 : 1c 83 std Y + 4 , r17 ; 0x04 E :\ PlatformIO \ DailyTimer / src / Config . cpp : 40 outCfg . afterResetTimeout = OUTPUTS_TIMEOUT_AFTER_RESET ; 35e4 : 85 e0 ldi r24 , 0x05 ; 5 35e6 : 8d 83 std Y + 5 , r24 ; 0x05 E :\ PlatformIO \ DailyTimer / src / Config . cpp : 42 eeprom_write_block (& outCfg , ( void *)( CONFIG_OUTS_OFFSET ), sizeof ( OutsCfg )); 35e8 : 45 e0 ldi r20 , 0x05 ; 5 35ea : 50 e0 ldi r21 , 0x00 ; 0 35ec : 68 e5 ldi r22 , 0x58 ; 88 35ee : 71 e0 ldi r23 , 0x01 ; 1 35f0 : ce 01 movw r24 , r28 35f2 : 01 96 adiw r24 , 0x01 ; 1 35f4 : 0e 94 d2 1e call 0x3da4 ; 0x3da4 < eeprom_write_block >
Как видно, это банальная запись в оперативку и вызов процедуры записи в EEPROM.
Этот дизасм - результат компиляции кода, написанного на C++ ардуиновским компилятором и без оптимизации.
_________________ I am DX168B and this is my favourite forum on internet!
Вернуться наверх
Kalisnik
Заголовок сообщения: Re: Как разбить двухбайтную переменную на 2 байта в СИ?
Добавлено: Ср дек 08, 2021 10:38:09
Зарегистрирован: Вс апр 18, 2021 15:43:55Сообщений: 430
Рейтинг сообщения: 0
DX168B , и ООП под силу AVR?
Добавлено after 1 hour 14 minutes 34 seconds: GoldenAndy , еще интересен момент...
Код:
uint8_t var[3] = {245, 235, 255}; uint8_t sum; sum = (var[0] + var[1] + var[2]) / 3;
Интересно как обрабатывается вычисление в скобках? Ведь там результат сложения явно будет больше одного байта. Но после деления все снова будет в нужном диапазоне. Куда запишется временный результат сложения в скобках и нужно ли заботится о том, что он выходит из допустимого диапазона чисел?
Вернуться наверх
DX168B
Заголовок сообщения: Re: Как разбить двухбайтную переменную на 2 байта в СИ?
Добавлено: Ср дек 08, 2021 10:40:17
Друг Кота
Карма: 25
Рейтинг сообщений: 99
Зарегистрирован: Вс янв 24, 2010 19:19:52Сообщений: 4468Откуда: Главный Улей России (Moscow)
Рейтинг сообщения: 1
Да. Если сильно не увлекаться полиморфизмом объектов и вместо прямого полиморфизма использовать полиморфизм через шаблоны классов.
_________________ I am DX168B and this is my favourite forum on internet!
Вернуться наверх
GoldenAndy
Заголовок сообщения: Re: Как разбить двухбайтную переменную на 2 байта в СИ?
Добавлено: Ср дек 08, 2021 10:54:29
Поставщик валерьянки для Кота
Карма: 66
Рейтинг сообщений: 536
Зарегистрирован: Чт июл 28, 2016 07:58:37Сообщений: 1925Откуда: Kyiv, UA
Рейтинг сообщения: 1
Вернуться наверх
Ivanoff-iv
Заголовок сообщения: Re: Как разбить двухбайтную переменную на 2 байта в СИ?
Добавлено: Ср дек 08, 2021 11:09:16
Друг Кота
Карма: 52
Рейтинг сообщений: 2114
Зарегистрирован: Пт ноя 11, 2016 05:48:09Сообщений: 7058Откуда: Сердце Пармы
Рейтинг сообщения: 1
Медали: 2
еще интересен момент...
тут лучше написать так:
Код:
uint8_t var[3] = {245, 235, 255}; uint8_t sum; sum = (uint16_t) (var[0] + var[1] + var[2]) / 3;
тогда компилятор для промежуточных вычислений зарезервирует 16 бит переменную (2 регистра), а результат запишет в 8 битную выходную переменную.
_________________ Для тех, кто не учил магию мир полон физики Безграмотно вопрошающим про силовую или высоковольтную электронику я не отвечаю, а то ещё посадят за участие в (само)убиении оболтуса...
Вернуться наверх
Страница 1 из 2
[ Сообщений: 27 ]
,
Кто сейчас на форуме
Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 23
Вы не можете начинать темы Вы не можете отвечать на сообщения Вы не можете редактировать свои сообщения Вы не можете удалять свои сообщения Вы не можете добавлять вложения