TransWikia.com

Read binary file into struct and also problems with endianness

Stack Overflow Asked on December 25, 2021

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

2 Answers

  • 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;
}

Answered by MikeCAT on December 25, 2021

struct teststruct *test; points to NULL, as it is defined in the global namespace. You do not allocate memory for this pointer, so test->version is UB.

fread(&test,sizeof(test),1,fp); is also wrong, this will read a pointer, not the content of the struct.

An easy fix is to change test to be a struct teststruct and not a pointer to it.

using namespace std;

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

struct teststruct test; //not a pointer anymore

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;
}

Answered by mch on December 25, 2021

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP