Преобразование Hex в Signed Int

RockHammer
Offline
Зарегистрирован: 21.08.2017

Здравствуйте. У меня есть 4 байта:  90 E3 04 00 (0x90, 0xE3, 0x04, 0x00)

И я знаю, что в Signed Int эти четыре байта равны числу 320400

Так вот, как сделать преобразование типов? 
То, что это именно 320400 мне сказал 010 editor.

P.s. эти байты должны считаться с карты NFC через rc522 ридер, но там в одном блоке 16 байтов, это только первые четыре. Как взять один блок и из него прочитать только первые четыре байта, а затем их преобразовать? 8 сектор, 0 блок, если это важно.

Спасибо.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Никак не надо преобразовывать. Положите свои байты в переменную типа long в правильном порядке и ничего делать не нужно - переменная сама станет равной 320400

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

RockHammer пишет:

Здравствуйте. У меня есть 4 байта:  90 E3 04 00 (0x90, 0xE3, 0x04, 0x00)

И я знаю, что в Signed Int эти четыре байта равны числу 320400

А вы батенька - ВРУН. Ай-яй-яй. Int в Ардуине умещается в двух байтах.

/**/
//---------------------------------------------
//-------компоновка--------------------------------------
//------main()---------------------------------------
void setup() {
  unsigned long num = 0x90E30400;
  Serial.begin(9600);
  Serial.println(num);// выводится 2430796800
  Serial.println((long)num);// выводится -1864170496
}

void loop() {
}
/*Скетч использует 1694 байт (5%) памяти устройства. Всего доступно 32256 байт.
  Глобальные переменные используют 186 байт (9%) динамической памяти, оставляя 1862 байт для локальных переменных. Максимум: 2048 байт.
*/

 

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

Порядок байт обратный

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

У Т.С. чихарда в исходных и выходных данных   0x4E390 == 320400

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

DetSimen пишет:

Порядок байт обратный

/**/
//---------------------------------------------
//-------компоновка--------------------------------------
//------main()---------------------------------------
void setup() {
  unsigned long num = 0x0004E390;
  Serial.begin(9600);
  Serial.println((long)num);// выводится 320400
}

void loop() {
}
/*Скетч использует 1584 байт (4%) памяти устройства. Всего доступно 32256 байт.
  Глобальные переменные используют 186 байт (9%) динамической памяти, оставляя 1862 байт для локальных переменных. Максимум: 2048 байт.
*/

 

Клапауций 112
Клапауций 112 аватар
Offline
Зарегистрирован: 01.03.2017

dimax пишет:

У Т.С. чихарда в исходных и выходных данных   0x4E390 == 320400

всё верно - Протоны должны бомбить Туву.

RockHammer
Offline
Зарегистрирован: 21.08.2017

qwone пишет:

RockHammer пишет:

Здравствуйте. У меня есть 4 байта:  90 E3 04 00 (0x90, 0xE3, 0x04, 0x00)

И я знаю, что в Signed Int эти четыре байта равны числу 320400

А вы батенька - ВРУН. Ай-яй-яй. Int в Ардуине умещается в двух байтах.


я имел ввиду, что 2 символа это один байт )) 

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

RockHammer пишет:

я имел ввиду, что 2 символа это один байт )) 

Вы не поняли, что хотел сказать Вам qwone.

В разных реализациях Си целый тип имеет различную длину. У Ардуино - это два байта, а на той платформе, с которой Вы читаете данные - 4.

В этом случае на Ардуино нужно использовать не int, а long (как Вам указал ЕвгенийП). Ну  и по порядку: младший байт идет первым.

RockHammer
Offline
Зарегистрирован: 21.08.2017

andriano пишет:

RockHammer пишет:

я имел ввиду, что 2 символа это один байт )) 

Вы не поняли, что хотел сказать Вам qwone.

В разных реализациях Си целый тип имеет различную длину. У Ардуино - это два байта, а на той платформе, с которой Вы читаете данные - 4.

В этом случае на Ардуино нужно использовать не int, а long (как Вам указал ЕвгенийП). Ну  и по порядку: младший байт идет первым.

что значит младший? меньший по значению?

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

RockHammer пишет:

что значит младший? меньший по значению?

https://ru.wikipedia.org/wiki/%D0%9F%D0%BE%D1%80%D1%8F%D0%B4%D0%BE%D0%BA...

GarryC
Offline
Зарегистрирован: 08.08.2016

Значит так - для начала, Вы ДОЛЖНЫ знать, какой байт старший и какой младший и в Вашем примере старший именно самый правый байт. Предположим, что эти 4 байта - элементы массива a[4] и имеют номера с 0 по 3 (слева направо).

А вот дальше преобразование (достаточно простое и правильное - это немаловажно) будет выглядеть приблизительно так
long l = (((((a[3]<<8)+a[2])<<8)+a[1])<<8)+a[0];

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Я бы через union или через указатель на байт положил бы и не парился бы.

GarryC
Offline
Зарегистрирован: 08.08.2016

Евгений, мы об этом уже говорили - это небезопасно (в смысле непереносимо на разные endian), но в данном конкретном случае вполне допустимо.
Но я всегда пропагандирую правильный подход, даже когда он не то, чтобы совершенно необходим.

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

ГарриС! Я вот подумал, аж вспотел, но ни одного пром.контроллера, из актуальных, и чтобы big endian, не вспомнил.

Это в порядке деMISRAизации ;).

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

GarryC пишет:

непереносимо на разные endian

Здесь форум по Ардуино. Вы можете назвать модель Ардуино для которой это создало бы проблемы?

GarryC пишет:

правильный подход

Правильность понятие не абсолютное. В разных местах разные вещи правильны.

GarryC
Offline
Зарегистрирован: 08.08.2016

AVR32 (оба семейства), STM8 - это из современных, с которыми я работал.
А из распространенных ранее с которыми я работал - ARM7, ARM1176 (по выбору) мотороллеры практически все (без вариантов).
Ну и конечно, Cortex M3 во всех видах, который bi-endian, Вы хотите рискнуть и поставить на то, что компилятор в конкретной среде на включен на big?

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

AVR32 и моторолы это да, про них забыл. И как-то стм-8 на ум не пришел. Спасибо!

АРМ, они би, а значит будут настроены как литл, что естественно.

Ведь понятно, что биг ендиан - извращение. ;)

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

GarryC пишет:

 Вы хотите рискнуть и поставить на то, что компилятор в конкретной среде на включен на big?

Я рискнуть - да Господь с Вами. Я Вас попросил назвать модель Ардуино, для которой мой код бы не работал. Назовёте - буду знать. Пока же Вы ничего не назвали, а вместо этого я слышу про какие-то моторолы, и прочие кортексы. Здесь форум про Ардуино - если Вы не заметили.

Что же касается переносимости между Ардуино и Кортексом, так её нет и не будет вовсе не из-за формата чисел :)

Ворота
Ворота аватар
Offline
Зарегистрирован: 10.01.2016

GarryC пишет:

я всегда пропагандирую правильный подход, 

GarryC пишет:

преобразование (достаточно простое и правильное - это немаловажно) будет выглядеть приблизительно так

long l = (((((a[3]<<8)+a[2])<<8)+a[1])<<8)+a[0];

Не в этот раз.

Достаточно запустить простейшёю проверку и убедиться в "правильности"

void setup() {
	Serial.begin(115200);
	const char unsigned a[] = { 1, 2, 3, 4 };
	
	const long l = (((((a[3]<<8)+a[2])<<8)+a[1])<<8)+a[0];
	
	Serial.print("l=");
	Serial.println(l, HEX);
}
void loop() {}

Если здесь "плохо видно", можно напечатать более наглядно, результат тот же.

#include <stdio.h>
static int serial_fputchar(const char ch, FILE *stream) { Serial.write(ch); return ch; }
static FILE *serial_stream = fdevopen(serial_fputchar, NULL);

void setup() {
	stdout = serial_stream; // эта строка первая в setup
	Serial.begin(115200);
	const char unsigned a[] = { 1, 2, 3, 4 };
	const long l = (((((a[3]<<8)+a[2])<<8)+a[1])<<8)+a[0];
	printf("l=0x%08lx\n", l);
}
void loop() {}

 

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Может так?

static int serial_fputchar(const char ch, FILE *stream) {
  Serial.write(ch);
  return ch;
}
static FILE *serial_stream = fdevopen(serial_fputchar, NULL);

void setup() {
  stdout = serial_stream; // эта строка первая в setup
  Serial.begin(9600);
  const char unsigned a[] = { '1', '2','3', '4' }; //< делать через ' '
  const long l = (((((a[3] << 8) + a[2]) << 8) + a[1]) << 8) + a[0];
  Serial.print("l=");
  Serial.println(l, HEX);// вывело l=3231
}
void loop() {}

 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

qwone пишет:

Может так?

  Serial.println(l, HEX);// вывело l=3231

Так неправильно ж вывело!? Зачем спрашивать "так или не так"?

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Ворота пишет:

Достаточно запустить простейшёю проверку и убедиться в "правильности"

Да ладно придираться, ну, забыл человек преобразовать тип. При первом же запуске увидит лажу и подправит.

Так-то понятно, что он имел в виду.

Ворота
Ворота аватар
Offline
Зарегистрирован: 10.01.2016

ЕвгенийП пишет:

Да ладно придираться, ну, забыл человек преобразовать тип. 

Когда человек врубает ментора и пишет

GarryC пишет:

я всегда пропагандирую правильный подход, 

GarryC пишет:

(достаточно простое и правильное - это немаловажно)

То, неплохо бы преобразовывать типы, и, что самое главное для программиста, проверять код перед публикацией.

Я нормально отоншусь к структурастам, мисрастам и прочим, считающим, что если из чемоданчика мастера выбросить половину инструментов, то качесво его работы улучшится, но лишь до тех пор, пока они не лезут везде с утверждениями, что их ересь - самая правоверная, и уж тем более не иллюстрируют это "простым, правильным, но неработающим" кодом.

GarryC
Offline
Зарегистрирован: 08.08.2016

Сначала никак не мог понять, что за проблема, на которую указал Ворота (а она действительно есть) - потом понял.
В последнее время чаще работаю под MinGW, естественно на х86 и там все нормально, но лишь потому, что там int имеет длину 32.
А для Ардуино, действительно, получается неверно, может быть, можно ключами компиляции вытащить, но это очень плохой путь и должно быть явно указано, что тип промежуточных результов (long)
long l = ((((((long)a[3]<<8)+(long)a[2])<<8)+(long)a[1])<<8)+(long)a[0];
Что интересно,

long l = ((((((long)a[3]<<8)+a[2])<<8)+a[1])<<8)+a[0]; или
long l = (((((a[3]<<8)+(long)a[2])<<8)+a[1])<<8)+a[0]; тоже приводит к верным разультатам, а вот
long l = (((((a[3]<<8)+a[2])<<8)+(long)a[1])<<8)+a[0]; все равно приводит к ошибке.

Недопустимая небрежность, спасибо за замечание, причем, когда писал код, возникла мысль, что надо бы сделать приведение, но попробовал в любимой среде (проверил перед публикацией) и увидел, что не надо, и так все получается  - решил не загромождать код и кстати, тем самым нарушил правило MISRA о длине по умолчанию.

Еще раз скажу - недопустимая небрежность, приношу извинения.