NatureFocus has asked for the wisdom of the Perl Monks concerning the following question:

Greetings,

I am trying to write a data file using a native C structure which has floats in it. Is this possible? My system is Windows XP with Visual C 6, and ActiveState perl. I am not trying to cross platforms, I just want to transfer from perl float to c float directly into a structure format. I could translate from a text file to the structure in c, but would rather do it in perl.

Enclosed are some sample code. I have tried pack with with "f" and "d", but end up with garbage in the structure.

#write test file open OUTF, ">c\\current\\test.bin"; binmode (OUTF); my $buff = pack "sfff", 99, 1.34, 1.44, 1.55; print OUTF $buff; print OUTF $buff; close OUTF; print "done.\n";
// test reader in visual c 6 typedef struct { short ss; float a,b,c; } TEST_REC; void iitest() { FILE *fd; TEST_REC tester[2]; long rv; fd = fopen("test.bin","r"); rv = fread( tester, sizeof(TEST_REC), 2, fd); printf(" ss %d, %5.3f, %5.3f, %5.3f, \n", tester[0].ss, tester[0]. +a,tester[0].b,tester[0].c); printf(" ss %d, %5.3f, %5.3f, %5.3f, \n", tester[1].ss, tester[1]. +a,tester[1].b,tester[1].c); fclose(fd); exit (0); }

Thanks. Eugene

UPDATE

The padding was the problem on the c side structure (padded to 4 bytes). I was already dealing with the padding elsewhere, but didn't think about it here. DUH! I was too focused on thinking the float was the problem.

I added the short as a sanity check, but since I was already insane...

Thanks.

Replies are listed 'Best First'.
Re: transfer float data to c
by jmcnamara (Monsignor) on Feb 14, 2007 at 17:33 UTC

    You can certainly do it using pack but you will have to take into account the alignment of the data in the struct.

    It is probably better to use Convert::Binary::C

    Here is an example from the docs:

    use Convert::Binary::C; #--------------------------------------------- # Create a new object and parse embedded code #--------------------------------------------- my $c = Convert::Binary::C->new->parse(<<ENDC); enum Month { JAN, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV, DEC }; struct Date { int year; enum Month month; int day; }; ENDC #----------------------------------------------- # Pack Perl data structure into a binary string #----------------------------------------------- my $date = { year => 2002, month => 'DEC', day => 24 }; my $packed = $c->pack('Date', $date);

    --
    John.

Re: transfer float data to c
by Zaxo (Archbishop) on Feb 14, 2007 at 17:31 UTC

    You probably need to look closely at both the Perl and C side of things to see what's wrong.

    Your C data structure may be padded as constructed by the compiler. A C debugger will tell you if it is. The short int is very likely to be padded to four bytes, or else the following float aligned to a four-byte boundary.

    Look at the perl side, too. You may find it easier to try importing a known good struct from C into a (binary) perl string and experimenting with its unpack decoding to find and verify the correct format string.

    After Compline,
    Zaxo