Как извлечь байты из переменной int (шестнадцатеричное значение хранится в переменной int)? - PullRequest
0 голосов
/ 07 февраля 2019

Я пытаюсь извлечь 4 байта из шестнадцатеричного значения, хранящегося в переменной int.

Моя идея состоит в том, чтобы «выдвинуть» требуемый байт в конец с помощью оператора сдвига вправо (>>), а затем использовать оператор AND сЗначение 0xFF, чтобы получить только последние 8 битов значения.Он отлично работает со значениями чисел (например, 73), но не работает со значениями af (например, 3f).Я попытался использовать различные форматы для printf, например% 02x, и я также попытался изменить маску для оператора AND на 0x000000FF.

int variable = 0x12cd34f4; 
char byte0, byte1, byte2, byte3; 

byte0 = (char)(variable & 0xFF);
byte1 = (char)((variable >> 8) & 0xFF);
byte2 = (char)((variable >> 16) & 0xFF);
byte3 = (char)((variable >> 24) & 0xFF);

printf("%x\n",byte0);// prints fffffff4 
printf("%x\n",byte1);// prints 34
printf("%x\n",byte2);//prints ffffffcd
printf("%x\n",byte3);//prints 12

Я ожидал, что он напечатает f4 для byte0, 34 для байта1, cd для байта2 и 12 для байта3, но фактический выход для байта0 равен fffffff4 и для байта2 ffffffcd .Я не понимаю, почему эти значения F добавляются и как я могу от них избавиться.

Ответы [ 4 ]

0 голосов
/ 07 февраля 2019

Ваши байтовые переменные объявлены как char, что в большинстве реализаций подписано.Когда вы передаете эти значения в printf, он не знает точный тип того, что вы передаете, потому что это функция с переменным числом аргументов.Таким образом, char аргументы получают повышение до int.И поскольку у вас есть значения, которые являются отрицательными, они получают знак расширения в рамках продвижения.

Измените тип этих переменных на unsigned char.Когда положительные значения затем повышаются до int, расширение знака не будет.

0 голосов
/ 07 февраля 2019

Во-первых, спецификатор формата %x без каких-либо модификаторов сам по себе предназначен для типа unsigned int, который, по-видимому, в вашей системе является 32-разрядным.

Наиболее значимые битыбайты F4 и CD равны 1. Это знаковый бит, поэтому он расширяется до целых 32 бит (отсюда FFFFFF), которые выводятся на печать.

Обратите внимание, чтокогда вы распечатываете их как %d, вы также видите бит знака в игре:

-12
52
-51
18

Чтобы решить эту проблему, вы можете сделать байты типа unsigned char, делать побитовые и на каждом printf аргумент с 0xFF и использование правильного спецификатора формата для unsigned char в шестнадцатеричном формате, то есть %hhX.

0 голосов
/ 07 февраля 2019

char может быть со знаком или без знака, это зависит от системы (и, возможно, также зависит от опций компилятора).

В вашем случае это, очевидно, signed.Значения между 0x80 и 0xFF (и не только значениями, начинающимися с 0xA0!) Имеют установленный бит # 7 и интерпретируются как значение со знаком (например, 0xFF равно -1, 0xF0 равно -16 и т. Д.).

При расширении их до int (это то, что происходит при вызове printf()), они расширяются до знака (это то, из чего происходят F s) и, таким образом, сохраняют свое "интерпретируемое значение".printf(), однако, предписано снова обращаться с ними как без знака, поэтому -16 представляется как 0xFFFFFFF0.

Либо используйте unsigned char соответственно.uint8_t или добавьте & 0xFF при звонке printf().

0 голосов
/ 07 февраля 2019

Just force char , чтобы быть unsigned :

#include <stdio.h>

int main()
{
  int variable = 0x12cd34f4; 
  unsigned char byte0, byte1, byte2, byte3; 

  byte0 = (char)(variable & 0xFF);
  byte1 = (char)((variable >> 8) & 0xFF);
  byte2 = (char)((variable >> 16) & 0xFF);
  byte3 = (char)((variable >> 24) & 0xFF);

  printf("%x\n",byte0);
  printf("%x\n",byte1);
  printf("%x\n",byte2);
  printf("%x\n",byte3);
}

Компиляция и выполнение:

pi@raspberrypi:/tmp $ gcc -pedantic -Wextra c.c
pi@raspberrypi:/tmp $ ./a.out
f4
34
cd
12

Обратите внимание, что & 0xFFбесполезны, когда у символа 8 бит

...