2016-06-28 3 views
2

Я чтение/запись в двоичный файл в формате мало-Endian от обратного порядка с использованием C и bswap_ {16,32,64} макросы из byteswap.h для байта -swapping.C 40 бит байт подкачки (обратный порядок байт)

Все значения считаются и записываются правильно, за исключением битового поля 40 бит.

Макрос bswap_40 не существует, и я не знаю, как это сделать или если возможно лучшее решение.

Вот небольшой код, показывающий эту проблему:

#include <stdio.h> 
#include <inttypes.h> 
#include <byteswap.h> 

#define bswap_40(x) bswap_64(x) 

struct tIndex { 
    uint64_t val_64; 
    uint64_t val_40:40; 
} s1 = { 5294967296, 5294967296 }; 

int main(void) 
{ 
    // write swapped values 
    struct tIndex s2 = { bswap_64(s1.val_64), bswap_40(s1.val_40) }; 
    FILE *fp = fopen("index.bin", "w"); 
    fwrite(&s2, sizeof(s2), 1, fp); 
    fclose(fp); 

    // read swapped values 
    struct tIndex s3; 
    fp = fopen("index.bin", "r"); 
    fread(&s3, sizeof(s3), 1, fp); 
    fclose(fp); 
    s3.val_64 = bswap_64(s3.val_64); 
    s3.val_40 = bswap_40(s3.val_40); 

    printf("val_64: %" PRIu64 " -> %s\n", s3.val_64, (s1.val_64 == s3.val_64 ? "OK" : "Error")); 
    printf("val_40: %" PRIu64 " -> %s\n", s3.val_40, (s1.val_40 == s3.val_40 ? "OK" : "Error")); 

    return 0; 
} 

Этот код компилируется с:

GCC -D_FILE_OFFSET_BITS = 64 -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE swap_40.c -o swap_40

Как определить макрос bswap_40 для чтения и записи этих значений 40 бит, выполняющих байты- замена?

ответ

6

Определяя bswap_40 быть таким же, как bswap_64, вы замена 8 байт вместо 5. Итак, если вы начинаете с этим:

00 00 00 01 02 03 04 05 

Вы в конечный итоге с этим:

05 04 03 02 01 00 00 00 

Вместо этого:

00 00 00 05 04 03 02 01 

Самый простой способ справиться с этим заключается в Tak е результат bswap_64 и правого сдвиг его на 24:

#define bswap_40(x) (bswap_64(x) >> 24) 
+0

Спасибо за решение, работать как шарм. –

1

EDIT

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

#define bswap40(s)            \ 
    ((((s)&0xFF) << 32) | (((s)&0xFF00) << 16) | (((s)&0xFF0000)) | \ 
    (((s)&0xFF000000) >> 16) | (((s)&0xFF00000000) >> 32)) 

использование:

s3.val_40 = bswap40(s3.val_40); 

... но это может быть проблема с оптимизатором. Я думаю, они должны быть оптимизированы для одного и того же.

Оригинал Сообщение

Я люблю ответ dbush лучше, ... Я собирался написать это:

static inline void bswap40(void* s) { 
    uint8_t* bytes = s; 
    bytes[0] ^= bytes[3]; 
    bytes[1] ^= bytes[2]; 
    bytes[3] ^= bytes[0]; 
    bytes[2] ^= bytes[1]; 
    bytes[0] ^= bytes[3]; 
    bytes[1] ^= bytes[2]; 
} 

Это деструктивный встроенная функция для переключения байт ...

+0

Спасибо, оптимизированная версия смешная. –

0

Я читаю/записываю двоичный файл в формате little-endian из big-endian, используя макросы C и bswap_ {16,32,64} из byteswap.h для байтовой замены.

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

unsigned char file_data[5]; 
// file data is in big endidan 
fread(file_data, sizeof file_data, 1, fp); 

uint64_t y = 0; 
for (i=0; i<sizeof file_data; i++) { 
    y <<= 8; 
    y |= file_data[i]; 
} 

printf("val_64: %" PRIu64 "\n", y); 

uint64_t val_40:40; не является переносимым. Диапазоны бит по другим типам, которые int, signed int, unsigned не являются переносимыми и имеют поведение, указанное в реализации.

КСТАТИ: Открыть файл в двоичном режиме :

// FILE *fp = fopen("index.bin", "w"); 
FILE *fp = fopen("index.bin", "wb"); 
Смежные вопросы