Search code examples
c++structendianness

Read binary file into struct and also problems with endianness


I want to read a binary file image.dd into struct teststruct *test;. Basically there are two problems:


1. Wrong order because of little / big endian.

printf("%02x", test->magic); just gives me 534b554c instead of 4c55b453 (maybe this has something to do with the "main problem" in the next part). Its just "one value". As an example, printf("%c", test->magic); gives L instead of LUKS.


2. No output with test->version.

uint16_t version; in struct teststruct gives no output. Which means, i call printf("%x ", test->version); and there is no result.


This is exampleh.h which contains struct:

#ifndef _EXAMPLEH_H
#define _EXAMPLEH_H

#define MAGIC_L     6

struct teststruct {
    char                magic [MAGIC_L];
    uint16_t            version;
};

#endif

This is the main code:

using namespace std;

#include <stdint.h>
#include <string.h>
#include <iostream>
#include <fstream>
#include "exampleh.h"

struct teststruct *test;

int main() {
    FILE *fp = fopen("C:\\image.dd", "rb");     // open file in binary mode

    if (fp == NULL) {
        fprintf(stderr, "Can't read file");
        return 0;
    }
    fread(&test,sizeof(test),1,fp);
    //printf("%x ", test->magic);   //this works, but in the wrong order because of little/big endian
    printf("%x ", test->version);   //no output at all

    fclose(fp);

    return 0;
}

And this here are the first 114 Bytes of image.dd:

4C 55 4B 53 BA BE 00 01 61 65 73 00 00 00 00 00 
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
00 00 00 00 00 00 00 00 78 74 73 2D 70 6C 61 69 
6E 36 34 00 00 00 00 00 00 00 00 00 00 00 00 00 
00 00 00 00 00 00 00 00 73 68 61 32 35 36 00 00 
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
00 00 00 00 00 00 00 00 00 00 10 00 00 00 00 40

Solution

    • You must allocate the structure and read data into the structure instead of reading into an pointer directly. If you are going to read only one structure, you won't need to declare pointers for the structure.
    • printf("%x ", test->magic); invokes undefined behavior because pointer (automatically converted from the array) is passed to where unsigned int is required.

    In this case, the observed behavior is because:

    Firstly, fread(&test,sizeof(test),1,fp); read the first few bytes from the file as pointer value.

    Then, printf("%02x", test->magic); printed the first 4-byte integer from the file because test->magic is (converted to) the pointer to the array placed at the top of the structure, and the address of the array is same as the address of the structure itself, so the address read from the file is printed. One more lucky is that where to read 4-byte integer and address (pointer) from as function arguments are the same.

    Finally, you didn't get any output from printf("%x ", test->version); because the address read from the file is unfortunately in region that is not readable and trying to read there caused Segmentation Fault.

    Fixed code:

    using namespace std;
    
    #include <stdint.h>
    #include <string.h>
    #include <iostream>
    #include <fstream>
    #include "exampleh.h"
    
    struct teststruct test; // allocate structure directly instead of pointer
    
    int main() {
        FILE *fp = fopen("C:\\image.dd", "rb");     // open file in binary mode
    
        if (fp == NULL) {
            fprintf(stderr, "Can't read file");
            return 0;
        }
        fread(&test,sizeof(test),1,fp); // now structure is read instead of pointer
        for (int i = 0; i < 6; i++) {
            printf("%02x", (unsigned char)test.magic[i]); // print using proper combination of format and data
        }
        printf(" ");
        printf("%x ", test.version); // also use . instead of ->
    
        fclose(fp);
    
        return 0;
    }