RE: Why GCC do this???

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



I mostly agree here.  If you really want the data to be portible, I wouldn't
even save it in binary.  For example, if you run a program on a sparc to
write the data using fwrite, and then read it on a PC, using fread, the bits
get all screwed up because of the endian issues involved (PCs are little
endian, sparcs are big endian).  Other architectures may have different
sizes for word and dword, and different alignment rules, etc.  You can solve
most of these by always writing in, say, big endian (using htons, htonl,
ntohs, etc.) but that won't get the alignment issues unless you write
individual items rather than the structure as a whole.

	Dave

-----Original Message-----
From: Eljay Love-Jensen [mailto:eljay@xxxxxxxxx]
Sent: Friday, May 14, 2004 6:41 AM
To: Andrea Pretto; gcc-help@xxxxxxxxxxx
Subject: Re: Why GCC do this???


Hi Andrea,

Claudio explained the __packed__ attribute, so I won't address that one
again.

That being said:  I *STRONGLY* recommend that you DO NOT do that.

Especially if you want your code to be platform agnostic.

If your OS or architecture changes, your code may fail.  If you COMPILER 
changes, your code may fail.  If someone adds another field in the 
structure, your code may fail.

In other words:  that coding practice is fraught with hazards!

For a canonical file format, use a byte-by-byte savvy input and output 
routine.  Do not use fread/fwrite.

If appropriate, I recommend the ntohs/ntohl for input, and htons/htonl for 
output.  Otherwise, do what you need for your custom input and output.

In your case, I assume you are using C and not C++.  In C++, you would 
encapsulate the read and write routines.

typedef struct BMP_H {
    word ID;
    dword size;
    dword res;
} BMP_H;

Note:  on 16-bit architecture, without alignment/padding, this structure is 
10 bytes.
Note:  on 32-bit architecture, without alignment/padding, this structure is 
20 bytes.
Note:  on 64-bit architecture, without alignment/padding, this structure is 
40 bytes.

Is that what you want?  Probably not.

#include <stdint.h>
typedef struct BMP_H {
    uint_least16_t ID; // Really should be char ID[2];
    uint_least32_t size;
    uint_least32_t res;
} BMP_H;

typedef char byte;
// Note:  routine does not care if char is signed or unsigned.
// Always treat byte as nonsigned (or sign indeterminate), just like char.
// This optimizes quite well.
extern byte getbyte(FILE* f); // Sets some error flag if EOF.
extern void putbyte(FILE* f, byte b); // Sets some error flag if file error.
void write_BMP_H(FILE* f, struct BMP_H* p)
{
    // Sequential "BM".  2 bytes.
    // This should have been char[2].
    // Since it's not, this is squirrelly.
    // Pretending little endian.
    p->ID = getbyte(f) & 0xFF;
    p->ID = (getbyte(f) & 0xFF) << 8;

    // Little endian size, 4 bytes.
    p->size = getbyte(f) & 0xFF
    p->size = (getbyte(f) & 0xFF) << 8;
    p->size = (getbyte(f) & 0xFF) << 16;
    p->size = (getbyte(f) & 0xFF) << 24;

    // Little endian.
    p->res = getbyte(f) & 0xFF
    p->res = (getbyte(f) & 0xFF) << 8;
    p->res = (getbyte(f) & 0xFF) << 16;
    p->res = (getbyte(f) & 0xFF) << 24;

    // Test error flag.  Yada yada yada.
}

void write_BMP_H(FILE* f, struct BMP_H* p)
{
    // Sequential "BM".  2 bytes.
    // This should have been char[2].
    // Since it's not, this is squirrelly.
    // Pretending little endian.
    putbyte(f, p->ID & 0xFF);
    putbyte(f, (p->ID >> 8) 0xFF);

    // Little endian size, 4 bytes.
    putbyte(f, p->size & 0xFF);
    putbyte(f, (p->size >> 8) & 0xFF);
    putbyte(f, (p->size >> 16) & 0xFF);
    putbyte(f, (p->size >> 24) & 0xFF);

    // Little endian.
    putbyte(f, p->res & 0xFF);
    putbyte(f, (p->res >> 8) & 0xFF);
    putbyte(f, (p->res >> 16) & 0xFF);
    putbyte(f, (p->res >> 24) & 0xFF);

    // Test error flag.  Yada yada yada.
}

You could make some helpers:
get2byte
get4byte
put2byte
put4byte

HTH,
--Eljay

[Index of Archives]     [Linux C Programming]     [Linux Kernel]     [eCos]     [Fedora Development]     [Fedora Announce]     [Autoconf]     [The DWARVES Debugging Tools]     [Yosemite Campsites]     [Yosemite News]     [Linux GCC]

  Powered by Linux