2014-09-19 5 views
0

У меня есть двоичный файл, и я хочу прочитать его двойной.Чтение double из двоичного файла (порядок байтов?)

В шестнадцатеричном представлении, у меня есть эти 8 байт в файле (а потом еще немного после этого):

40 28 25 с8 9бов 77 27 с9 40 28 98 80 8 8б 2b d5 40 ...

Это должно соответствовать двойному значению около 10 (в зависимости от того, что означает эта запись).

Я использовал

#include<stdio.h> 
#include<assert.h> 

int main(int argc, char ** argv) { 
    FILE * f = fopen(argv[1], "rb"); 
    assert(f != NULL); 
    double a; 
    fread(&a, sizeof(a), 1, f); 
    printf("value: %f\n", a); 
} 

Однако, что печатает значение: -261668255698743527401808385063734961309220864,000000

Итак, ясно, что байты не преобразуется в двойной правильно. Что происходит? Используя ftell, я могу подтвердить, что читается 8 байтов.

+3

Где код, который ** написал ** эти «байты», и был ли он с той же платформы? – WhozCraig

+0

Похоже, что исходная система записывала данные как большие конечные элементы, и вы пытаетесь прочитать ее как маленький endian - вам просто нужно изменить порядок 8 байтов. –

+1

Btw, '12.0738' для первого,' 12.2979' для второго и т. Д., Если вы меняете байты, поэтому ... обратные байты, если читаете на платформе LE. Я искренне надеюсь, если вы сделаете это * все * платформы * напишите * данные в BE. – WhozCraig

ответ

1

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

#include <stdio.h> 
#include <stdint.h> 

uint64_t byteswap64(uint64_t input) 
{ 
    uint64_t output = (uint64_t) input; 
    output = (output & 0x00000000FFFFFFFF) << 32 | (output & 0xFFFFFFFF00000000) >> 32; 
    output = (output & 0x0000FFFF0000FFFF) << 16 | (output & 0xFFFF0000FFFF0000) >> 16; 
    output = (output & 0x00FF00FF00FF00FF) << 8 | (output & 0xFF00FF00FF00FF00) >> 8; 
    return output; 
} 

int main() 
{ 
    uint64_t bytes = 0x402825c89b7727c9; 
    double a = *(double*)&bytes; 
    printf("%f\n", a); 

    bytes = byteswap64(bytes); 
    a = *(double*)&bytes; 
    printf("%f\n", a); 

    return 0; 
} 

Тогда выход

 
12.073796 
-261668255698743530000000000000000000000000000.000000 

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

+0

Благодарим вас за подробный ответ. В конце я использовал fgetc с профсоюзным трюком из stackoverflow.com/questions/4949144/how-to-byteswap-a-double – j13r

1

Endianness - соглашение. Читатель и писатель должны договориться о том, какой смысл использовать и придерживаться.

Вы должны прочитать свой номер как int64, convert endianness, а затем бросить в двойное.

+2

Кастинг не будет работать, если вы хотите повторно интерпретировать одни и те же биты. Casting преобразует (очень большое) целое число в очень большое 'double'. – unwind

+0

Работает с указателем или литье; последний является более безопасным в случае несоответствия размера, поскольку, по крайней мере, вы знаете, что он не будет переполняться рядом с переменными. – Medinoc

Смежные вопросы