Как преобразовать в целое число символ [4] из "шестнадцатеричных" чисел [C / Linux] - PullRequest
0 голосов
/ 27 марта 2020

Итак, я работаю с системными вызовами в Linux. Я использую "lseek" для навигации по файлу и "читать", чтобы прочитать. Я также использую Midnight Commander, чтобы увидеть файл в шестнадцатеричном формате. Следующие 4 байта, которые я должен прочитать, имеют младший порядок и выглядят так: «2A 00 00 00». Но, конечно, байты могут быть чем-то вроде «2A 5F B3 00». Я должен преобразовать эти байты в целое число. Как мне подойти к этому? Моей первоначальной мыслью было прочитать их в виде вектора из 4 символов, а затем построить оттуда целое число, но я не знаю, как. Есть идеи?

Позвольте привести пример того, что я пробовал. У меня есть следующие байты в файле "44 00". Я должен преобразовать это в значение 68 (4 + 4 * 16):

char value[2];
read(fd, value, 2);
int i = (value[0] << 8) | value[1];

Переменная я 17480 из 68.

ОБНОВЛЕНИЕ: Nvm. Я решил это. Я смешал индексы, когда я сдвигаюсь. Это должно быть значение [1] << 8 ... | значение [0] </p>

Ответы [ 2 ]

0 голосов
/ 27 марта 2020

Общие соображения

Кажется, что вопрос состоит из нескольких частей - по крайней мере, как читать данные, какой тип данных использовать для хранения промежуточного результата и как выполнить преобразование. Если вы действительно предполагаете, что представление в файле состоит из байтов 32-разрядного целого числа в порядке с прямым порядком байтов, причем все биты значимы, то, вероятно, я бы не использовал char[] в качестве промежуточного, а скорее uint32_t или int32_t. Если вы знаете или предполагаете, что порядковый номер данных совпадает с исходным порядковым номером машины, то вам не нужны никакие другие.

Определение собственного порядкового номера

Если вам нужно вычислить Собственный порядковый номер хоста, тогда это будет сделано:

static const uint32_t test = 1;
_Bool host_is_little_endian = *(char *)&test;

Это стоит сделать, потому что вполне может быть так, что вам вообще не нужно делать никаких преобразований.

Чтение данных

Я бы считал данные в uint32_t (или, возможно, int32_t), а не в массив char. Возможно, я бы прочитал его в массив uint8_t.

uint32_t data;
int num_read = fread(&data, 4, 1, my_file);
if (num_read != 1) { /* ... handle error ... */ }

Преобразование данных

Стоит знать, соответствует ли представление в файле порядку байтов хоста, потому что если это так вам не нужно выполнять какие-либо преобразования (то есть, вы сделали на данном этапе в этом случае). Однако если вам нужно поменять местами порядковый номер, вы можете использовать ntohl() или htonl():

if (!host_is_little_endian) {
    data = ntohl(data);
}

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

Подписано целые числа

Если вам нужно целое число без знака, то вы можете сделать то же самое, но использовать объединение:

union {
    uint32_t unsigned;
    int32_t signed;
} data;

Во всех предыдущих случаях используйте data.unsigned вместо простой data и в конце зачитайте подписанный результат из data.signed.

0 голосов
/ 27 марта 2020

Предположим, вы указали в свой буфер:

unsigned char *p = &buf[20];

, и вы хотите видеть следующие 4 байта как целое число и назначить их вашему целому числу, тогда вы можете cast it:

int i;
i = *(int *)p;

Вы только что сказали, что p теперь является указателем на int, вы отменили ссылку на этот указатель и присвоили его i.

Однако это зависит от порядкового номера вашей платформы , Если ваша платформа имеет другой порядок байтов, вам, возможно, придется сначала скопировать байты в небольшой буфер, а затем использовать эту технику. Например:

unsigned char ibuf[4];
for (i=3; i>=0; i--) ibuf[i]= *p++;
i = *(int *)ibuf;


РЕДАКТИРОВАТЬ

Предложения и комментарии Эндрю Хенле и Бодо могут дать:

unsigned char *p = &buf[20];
int i, j;

unsigned char *pi= &(unsigned char)i;
for (j=3; j>=0; j--) *pi++= *p++;

// and the other endian:
int i, j;
unsigned char *pi= (&(unsigned char)i)+3;
for (j=3; j>=0; j--) *pi--= *p++;
...