Questo non è l'errore di fread
, ma della CPU, che è (apparentemente) little-endian. Cioè, la tua CPU considera il primo byte in un valore short
come lo basso 8 bit, piuttosto che (come sembra che tu abbia aspettato) gli 8 bit più alti.
Ogni volta che si legge un formato di file binario, è necessario convertire in modo esplicito dall'endianness del formato del file alla endianità nativa della CPU. Lo fate con funzioni come questi:
/* CHAR_BIT == 8 assumed */
uint16_t le16_to_cpu(const uint8_t *buf)
{
return ((uint16_t)buf[0]) | (((uint16_t)buf[1]) << 8);
}
uint16_t be16_to_cpu(const uint8_t *buf)
{
return ((uint16_t)buf[1]) | (((uint16_t)buf[0]) << 8);
}
Voi fate il vostro fread
in un uint8_t
buffer di dimensione appropriata, e quindi copiare manualmente tutti i dati byte sopra al vostro BMPHeader
struct, la conversione, se necessario. Che qualcosa sarebbe simile a questa:
/* note adjustments to type definition */
typedef struct BMPHeader
{
uint8_t magic_number[2];
uint32_t file_size;
uint8_t reserved[4];
uint32_t data_offset;
} BMPHeader;
/* in general this is _not_ equal to sizeof(BMPHeader) */
#define BMP_WIRE_HDR_LEN (2 + 4 + 4 + 4)
/* returns 0=success, -1=error */
int read_bmp_header(BMPHeader *hdr, FILE *fp)
{
uint8_t buf[BMP_WIRE_HDR_LEN];
if (fread(buf, 1, sizeof buf, fp) != sizeof buf)
return -1;
hdr->magic_number[0] = buf[0];
hdr->magic_number[1] = buf[1];
hdr->file_size = le32_to_cpu(buf+2);
hdr->reserved[0] = buf[6];
hdr->reserved[1] = buf[7];
hdr->reserved[2] = buf[8];
hdr->reserved[3] = buf[9];
hdr->data_offset = le32_to_cpu(buf+10);
return 0;
}
Fate non scontato che endianness della CPU è lo stesso del formato di file anche se si sa per certo che in questo momento sono la stessa cosa; tu scrivi comunque le conversioni, così che in futuro il tuo codice funzionerà senza modifiche su una CPU con l'endianità opposta.
Si può rendere la vita più facile per te, utilizzando i tipi <stdint.h>
larghezza fissa, utilizzando i tipi senza segno a meno che non essere in grado di rappresentare i numeri negativi è assolutamente necessario, e non utilizzando numeri interi quando array di caratteri faranno. Ho fatto tutte queste cose nell'esempio sopra. Puoi vedere che non devi preoccuparti di convertire il numero magico di endian, perché l'unica cosa che devi fare è testare magic_number[0]=='B' && magic_number[1]=='M'
.
conversione nella direzione opposta, a proposito, si presenta come segue:
void cpu_to_le16(uint8_t *buf, uint16_t val)
{
buf[0] = (val & 0x00FF);
buf[1] = (val & 0xFF00) >> 8;
}
void cpu_to_be16(uint8_t *buf, uint16_t val)
{
buf[0] = (val & 0xFF00) >> 8;
buf[1] = (val & 0x00FF);
}
Conversione di 32- quantitativi/64-bit lasciato come esercizio.
... il pasticcio del pane con l'ordine del morso? Hai provato a mordicchiare? – Mehrdad
Non è questo 'fread' invece di' bread' per il tuo titolo? – buruzaemon
scusate. Devo ancora utilizzare correttamente Auto Lions. L'ho risolto –