Johannes Bauer
Johannes Bauer

Reputation: 528

Reading binary data written using Python struct in C

I'm writing a binary file in Python to be read in C. The (MWE) code to write the file is:

import struct

with open('test.bin', 'wb') as outfile:  
    outfile.write(struct.pack('didi', 1.2, 1, 1.3, 2))

When I read the file in C, I get garbled data:

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

int main(int argc, char *argv[]) {
    double testdouble, testdoubletwo;
    int testint, testinttwo;

    FILE *f = fopen("test.bin", "rb");
    assert(f);

    assert(fread(&testdouble, sizeof(testdouble), 1, f));
    assert(fread(&testint, sizeof(testint), 1, f));
    assert(fread(&testdoubletwo, sizeof(testdoubletwo), 1, f));
    assert(fread(&testinttwo, sizeof(testinttwo), 1, f));

    fprintf(stderr, "testdouble: %f, testint: %d, testdouble: %f, testinttwo: %d", testdouble, testint, testdoubletwo, testinttwo);

    return 0;
}

Output:

testdouble: 1.200000, testint: 1, testdouble: -92559641157289301412905710012271939667257667601819249288413184.000000, testinttwo: 1073007820

If I leave out the integers, it works for this small example, but not for my actual problem where I'm reading a few dozen doubles. Some of them (not the first, not the last) end up garbled.

System: Ubuntu 12.04, 64bit
Python: 2.7.3

Upvotes: 1

Views: 1460

Answers (3)

//  BY: Ishraga Mustafa Awad Allam. ON: 22-2-2020

#include <stdio.h>
#include <stdlib.h>

struct rec {
    int i;
    float r;
    char str[10];
    }rc;

int main(){
   FILE *f1;
   float f;
   int j = 0;


f1 = fopen("c:\\code\\python\\dfile.dat", "r");// or exit("Unable to open file!");

  while(!feof(f1)) {
     j++;
     fread(&rc, sizeof(rec), 1, f1);
     printf("%4d %4d %12.6f %s \n", j, rc.i, rc.r, rc.str);

     }

printf("\nGOOD TERMINATION \n");

fclose(f1);


getchar();
return 0;
}

Upvotes: 0

Robert Jacobs
Robert Jacobs

Reputation: 3360

I should also say that it is possible to change the C program and not the python program to work. This is almost perfect except that on my system python writes a 28 byte file, and my C program expects 32 bytes. It works without the assert. Not ideal. Writing a junk int after testinttwo would fix the problem.

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

int main(int argc, char *argv[]) {
    typedef struct { double testdouble;
                     int testint;
                     double testdoubletwo;
                     int testinttwo;
                } teststruct;
    teststruct abc;
    FILE *f = fopen("test.bin", "rb");
    assert(f);
/*  assert(fread(&abc, sizeof(teststruct), 1, f));*/
    printf("sizeof(teststruct) %d\n",sizeof(teststruct));
    fread(&abc, sizeof(teststruct), 1, f);

    fprintf(stderr, "testdouble: %f, testint: %d, testdouble: %f, testinttwo: %d", abc.testdouble, abc.testint, abc.testdoubletwo, abc.testinttwo);

    fclose(f);
    return 0;
}

Adjusted python program to fix the assert issue.

import struct

with open('test.bin', 'wb') as outfile:
    outfile.write(struct.pack('didii', 1.2, 1, 1.3, 2,0))

C Output:

sizeof(teststruct) 32
testdouble: 1.200000, testint: 1, testdouble: 1.300000, testinttwo: 2

Upvotes: 0

PasteBT
PasteBT

Reputation: 2198

In your C code, you read every item out one by one, which means you did not apply any alignment. Try this:

outfile.write(struct.pack('=didi', 1.2, 1, 1.3, 2))

hexdump test.bin

0000000 3333 3333 3333 3ff3 0001 0000 cccd cccc
0000010 cccc 3ff4 0002 0000                    

C code output:

testdouble: 1.200000, testint: 1, testdouble: 1.300000, testinttwo: 2

If you not change python code, still use 'didi', then change c code like this:

struct D {
    double td;
    int ti;
    double td2;
   int ti2;
};


struct D d;
fread(&d, sizeof(struct D), 1, f);
fprintf(stderr, "testdouble: %f, testint: %d, testdouble: %f, testinttwo: %d", d.td, d.ti, d.td2, d.ti2);

This test on Fedora 17, using python 2.7.3, gcc 4.7.2, I prefer define the structure.

Upvotes: 1

Related Questions