Newbie SDL_endian question

hiya,

…I’m undertaking my first fight with porting a game from x86 to ppc
(OS X), and want a little reassurance that I’m doing the right thing
with the byte swapping…

I didn’t find any info in the installed SDL docs, but saw this page
(http://www.libsdl.org/intro/usingendian.html), which showed how to
swap a 16 byte value…my confusion comes with how to correctly swap
struct’s that are read in as a chunk, like in the following:

typedef struct VP_FILE_HEADER {
char id[4];
int version;
int index_offset;
int num_files;
} VP_FILE_HEADER;

VP_FILE_HEADER VP_header;

Assert( sizeof(VP_header) == 16 );
fread(&VP_header, 1, sizeof(VP_header), fp);

…as it is right now, the VP_header.id comes out fine, but the rest
come out kinda whacked…should I use a function to replace the
fread() (along the lines of the “intro” example), or should this be
done as a set of macros?

slowly outta th’gate,
jamie

NEVER read in structs as a chunk!
As well as endian issues
you also have to deal with packing issues
as well type size issues.

Write functions to read/write all of the inbuilt types which also
perform byte swapping for you.
Then write a read/write function for each structs which call other
functions to read/write each member.

As a debugging/verification aid you can also read/write the size and type.
Also use typedefs/defines for int sizes ie int8, int16, int32.

tigital wrote:> hiya,

…I’m undertaking my first fight with porting a game from x86 to ppc
(OS X), and want a little reassurance that I’m doing the right thing
with the byte swapping…

I didn’t find any info in the installed SDL docs, but saw this page
(http://www.libsdl.org/intro/usingendian.html), which showed how to swap
a 16 byte value…my confusion comes with how to correctly swap struct’s
that are read in as a chunk, like in the following:

typedef struct VP_FILE_HEADER {
char id[4];
int version;
int index_offset;
int num_files;
} VP_FILE_HEADER;

VP_FILE_HEADER VP_header;

Assert( sizeof(VP_header) == 16 );
fread(&VP_header, 1, sizeof(VP_header), fp);

…as it is right now, the VP_header.id comes out fine, but the rest
come out kinda whacked…should I use a function to replace the fread()
(along the lines of the “intro” example), or should this be done as a
set of macros?

slowly outta th’gate,
jamie

At 11:57 PM 8/13/02 -0400, you wrote:

hiya,

…I’m undertaking my first fight with porting a game from x86 to ppc (OS
X), and want a little reassurance that I’m doing the right thing with the
byte swapping…

I didn’t find any info in the installed SDL docs, but saw this page
(http://www.libsdl.org/intro/usingendian.html), which showed how to swap a
16 byte value…my confusion comes with how to correctly swap struct’s
that are read in as a chunk, like in the following:

In a struct (or any other ordered data structure), the order of the
elements is preserved, but the order of the bytes in short, int, long, and
long long (at least) are dependant on your system’s endianness. In your
case, you want to convert the ints that you read to big-endian values [or
write them that way when you save the file].–
“It startled him even more when just after he was awarded the Galactic
Institute’s Prize for Extreme Cleverness he got lynched by a rampaging mob
of respectable physicists who had finally realized that the one thing they
really couldn’t stand was a smart-ass.”
– Hitchhiker’s Guide to the Galaxy

At 02:12 PM 8/14/02 +1000, you wrote:

NEVER read in structs as a chunk!
As well as endian issues
you also have to deal with packing issues
as well type size issues.

I’ve dealt with some of this in a little bit of network code – I’m not
sure if “NEVER” is the best guideline.

Use caution, yes – the issues are quite valid. Only use component types
of defined size, definitely.

Packing is possible, though, if you’re absolutely sure to use all of your
compiler’s packing options for that section of code. #pragma pack(1)
becomes extremely useful when you’re trying to create a 15-byte network packet.–
“It startled him even more when just after he was awarded the Galactic
Institute’s Prize for Extreme Cleverness he got lynched by a rampaging mob
of respectable physicists who had finally realized that the one thing they
really couldn’t stand was a smart-ass.”
– Hitchhiker’s Guide to the Galaxy

I recommed NEVER not to imply its not possible but that it will save
time in the long run
especially if you are not the only who will use the code.

Christopher Subich wrote:> At 02:12 PM 8/14/02 +1000, you wrote:

NEVER read in structs as a chunk!
As well as endian issues
you also have to deal with packing issues
as well type size issues.

I’ve dealt with some of this in a little bit of network code – I’m not
sure if “NEVER” is the best guideline.

Use caution, yes – the issues are quite valid. Only use component
types of defined size, definitely.

Packing is possible, though, if you’re absolutely sure to use all of
your compiler’s packing options for that section of code. #pragma
pack(1) becomes extremely useful when you’re trying to create a 15-byte
network packet.


“It startled him even more when just after he was awarded the Galactic
Institute’s Prize for Extreme Cleverness he got lynched by a rampaging
mob of respectable physicists who had finally realized that the one
thing they really couldn’t stand was a smart-ass.”
– Hitchhiker’s Guide to the Galaxy

I recommed NEVER not to imply its not possible but that it will save
time in the long run
especially if you are not the only who will use the code.

Christopher Subich wrote:

At 02:12 PM 8/14/02 +1000, you wrote:

NEVER read in structs as a chunk!
As well as endian issues
you also have to deal with packing issues
as well type size issues.

I’ve dealt with some of this in a little bit of network code – I’m
not sure if “NEVER” is the best guideline.

Use caution, yes – the issues are quite valid. Only use component
types of defined size, definitely.

Packing is possible, though, if you’re absolutely sure to use all
of your compiler’s packing options for that section of code.
#pragma pack(1) becomes extremely useful when you’re trying to
create a 15-byte network packet.

well, I just tried:

     if ( SDL_BYTEORDER == SDL_BIG_ENDIAN ) {
         VP_header.version = SDL_Swap32( VP_header.version);
         VP_header.index_offset = SDL_Swap32( VP_header.index_offset);
         VP_header.num_files = SDL_Swap32( VP_header.num_files);
     }

…which seems to give correct results!

tanx for the push in the right direction!

jamie

I’ve dealt with some of this in a little bit of network code – I’m not
sure if “NEVER” is the best guideline.

Never is the best guideline.

Either send as individual units, or pack it manually, or whatnot.

#pragma pack()” isn’t a universal solution, nor does it help with byte
swapping.

It is EASY to serialize objects when you first write disk/network code,
and it is a severe motherf***er to do it later. The bugs are subtle, hard
to find, and viscious.

You have been warned. Do it right the first time.

–ryan.

     if ( SDL_BYTEORDER == SDL_BIG_ENDIAN ) {
         VP_header.version = SDL_Swap32( VP_header.version);
         VP_header.index_offset = SDL_Swap32( VP_header.index_offset);
         VP_header.num_files = SDL_Swap32( VP_header.num_files);
     }

…which seems to give correct results!

Even better:

VP_header.version = SDL_SwapLE32(VP_header.version);
VP_header.index_offset = SDL_SwapLE32(VP_header.index_offset);
VP_header.num_files = SDL_SwapLE32(VP_header.num_files);

Which says "take this 32bit littleendian (intel) data and convert it to
the native byte order.

On x86, this dithers down to:

VP_header.version = VP_header.version;
VP_header.index_offset = VP_header.index_offset;
VP_header.num_files = VP_header.num_files;

If you’re lucky, your compiler might optimize that out altogether. On
PowerPC, it’ll be a byte-swapping macro.

–ryan.