Конвертировать / извлечь целые числа из массива символов - PullRequest
3 голосов
/ 11 октября 2011

Я получил cstring, исходящий от звонка из gzread. Я знаю, что данные являются блоками, и каждый блок состоит из беззнаковых int, char, int и unsigned short int.

Так что мне было интересно, каков стандартный способ разбиения этого cstring на соответствующие переменные.

Скажем, первые 4 байта - это целое число без знака, следующий байт - символ, следующие 4 байта - со знаком int, а последние 2 байта - короткое целое без знака.

//Some pseudocode below which would work
char buf[11];
unsigned int a;
char b;
int c;
unsigned short int d;

Полагаю, я мог бы использовать memcpy с соответствующими смещениями.

memcpy(&a, buf, sizeof(unsigned int));
memcpy(&b, buf+4, sizeof(char));
memcpy(&c, buf+5, sizeof(int));
memcpy(&d, buf+9, sizeof(unsigned short int));

Или лучше использовать несколько битоператоров? Как смещение и маскировка.

Или лучше было бы сжать все 11 байтов непосредственно в какую-то структуру, или это вообще возможно? Исправлена ​​ли структура памяти структуры, и будет ли это работать с gzread?

Ответы [ 4 ]

2 голосов
/ 11 октября 2011

Вы должны убедиться, что порядок байтов файла соответствует архитектуре процессора, на котором вы выполняете свой код.Например, если целые числа записываются в файл с самым старшим байтом в первую очередь, а ваш процессор использует наименее значимый байт в первом порядке, вы получаете мусор для результатов.В другой архитектуре вы должны заключить все операции чтения и записи для целых чисел в макросы или встроенные функции, управляющие порядком байтов для вас в зависимости от архитектуры целевого процессора.

2 голосов
/ 11 октября 2011

Если вы упакуете структуру (прочитайте атрибут __packed__), вы можете положиться на порядок и то, что члены не выровнены. Следовательно, вы можете читать в структуру напрямую. Однако я не уверен в переносимости этого решения.

В противном случае используйте указатель магии и приведение типа так:

char *buffer;
int a = *(reinterpret_cast<int*> (buffer))
unsigned short b = *(reinterpret_cast<unsigned short*> (buffer + sizeof(int)))
1 голос
/ 11 октября 2011

Вам нужно указать формат, прежде чем вы сможете что-либо сделать. Является это текстовый или двоичный файл (предположительно двоичный из вашего описания, но один никогда не знает) Какое представление используется для подписанных значений? Какие порядок байтов? memcpy будет работать только если ваша архитектура машины точно соответствует формату ввода - редкий случай сегодня, поскольку почти все сетевые форматы имеют порядок байтов и являются наиболее распространенными архитектуры с прямым порядком байтов (Большинство форматов и архитектур сегодня используйте дополнение 2 для отрицательных значений, так что вы часто можете «принять» совместимость там. Но есть и исключения.)

Учитывая это, математическая реконструкция значения (с использованием маскировки и сдвиг, или умножения) является единственным переносимым решением. в зависимости на машине и качество компилятора, это может легко привести в лучшем исполнении.

1 голос
/ 11 октября 2011

Зависит от того, как определены входные данные.Если он определен в порядке порядкового номера хоста (то есть порядок байтов всегда совпадает с системой, в которой выполняется ваш код), то показанный вами memcpy() является хорошим переносимым методом для использования.

В качестве альтернативы, если входные данные определены с определенным порядком байтов, то лучшее переносимое решение - загружать их по одному unsigned char за раз, используя сдвиги и побитовые или.

...