Как прочитать 5 байтов значимого uint64_t в C? - PullRequest
0 голосов
/ 23 мая 2011

Мне нужно выделить массив uint64_t[1e9], чтобы сосчитать что-то, и я знаю, что элементы находятся между (0,2 ^ 39).Поэтому я хочу calloc 5 * 1e9 байтов для массива.

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

Должно быть 2 способа.

Один из них - сначала проверить порядок байтов, чтобы мы могли memcpy 5 байтов либо первым, либо последним из целых 8 байтов.

Другойсостоит в том, чтобы использовать 5 битное смещение, а затем бит или их вместе.

Я думаю, что первое должно быть быстрее.

Итак, в системе GCC, libc или GNU есть ли заголовочный файл для указанияявляется ли текущая система Little Endian или Big Endian?Я знаю, что x86_64 - это Little Endian, но я не люблю писать непереносимый код.

Конечно, приветствуются любые другие идеары.

Добавить:

Мне нужно использоватьМассив для подсчета множества строк использует хеширование в левом направленииЯ планирую использовать 21 бит для ключа и 18 бит для подсчета.

Ответы [ 3 ]

1 голос
/ 23 мая 2011

Когда вы говорите «быстрее» ... как часто выполняется этот код? 5 раз <<8 плюс |, вероятно, стоит меньше 100 нс. Таким образом, если этот код выполняется 10 000 раз, это добавляет до 1 (одной) секунды.

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

Тем не менее, решение для определения порядка байтов просто:

int a = 1;
char * ptr = (char*)&a;
bool littleEndian = *ptr == 1;

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

Или вы могли бы просто сдвинуться или пять раз ...

РЕДАКТИРОВАТЬ Полагаю, я немного неправильно понял ваш вопрос. Вы говорите, что хотите использовать младшие 5 байтов (= 40 бит) uint64_t в качестве счетчика, да?

Таким образом, операция будет выполняться много, много раз. Опять же, memcpy совершенно бесполезен. Давайте возьмем число 0x12345678 (32 бита). В памяти это выглядит так:

0x12 0x34 0x56 0x78    big endian
0x78 0x56 0x34 0x12    little endian

Как видите, байты меняются местами. Таким образом, для преобразования между ними вы должны либо использовать сдвиг битов, либо замену байтов. memcpy не работает.

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

 key = item & 0x1FFFFF
 count = (item >>> 21)

читать и

 item = count << 21 | key

написать. Теперь вам просто нужно собрать ключ из пяти байтов, и все готово:

 key = (((hash[0] << 8) | (hash[1]<<8)) | ....

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

Кажется, у вас есть массив из 40-битных целых, и вы хотите читать / записывать этот массив.

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

Другое решение заключается в использовании двух массивов:

int lower[];
unit8_t upper[]

, то есть: Сохранить биты 33-40 в массиве second . Для чтения / записи значений требуется одна смена + or.

0 голосов
/ 23 мая 2011

Ну, я просто обнаружил, что заголовки ядра поставляются с <asm/byteorder.h>.

встроенный memcpy в while(i<x+3){++*i=++*j} может все еще работать медленнее, поскольку операция кэширования выполняется медленнее, чем регистры.

другой способ для memcpy:

union dat {
 uint64_t a;
 char b[8];
} d;
0 голосов
/ 23 мая 2011

Если вы рассматриваете числа как числа, а не как массив байтов, ваш код будет независимым от порядка байтов.Следовательно, я бы выбрал решение shift и или .

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

...