The FB Compiler always produces traditional Mac big-endian PPC code. On an Intel Mac, such apps are run in Rosetta and thus keep their big-endian property. FBtoC can produce either big-endian or little-endian or both, depending on the Architecture setting (PPC, Intel, Universal).
Many FB programs, when run in little-endian mode for the first time, turn out to have bugs. Endian bugs affect multibyte numeric variables: short, long, pointer, single and double (along with synonyms: SInt16, SInt32, ptr...). Strings and 1-byte numeric vars (char, unsigned byte, UInt8...) are not affected directly by endianness.
Byte order in memory
As an illustrative example, consider how we might display the most- and least-significant byes of a short variable.
dim as short myShortVar dim as byte lsByte, msByte myShortVar = 1 print , "msByte", "lsByte" ... rest of program follows later... Output (on Intel Mac): msByte lsByte buggy method 1 0 fix 1 0 1 fix 2 0 1 fix 3 0 1 fix 4 0 1
print "buggy method", msByte = peek( @myShortVar ) // endian bug on Intel lsByte = peek( @myShortVar + 1 ) // endian bug on Intel print msByte, lsByte
print "fix 1", #if def _LITTLEENDIAN // Intel msByte = peek( @myShortVar + 1 ) // byte 1 lsByte = peek( @myShortVar ) // byte 0 #else // PPC msByte = peek( @myShortVar ) // byte 0 lsByte = peek( @myShortVar + 1 ) // byte 1 #endif /* def _LITTLEENDIAN */ print msByte, lsByte
print "fix 2", include "Tlbx CFByteOrder.incl" myShortVar = fn CFSwapInt16HostToBig( myShortVar ) // myShortVar is now certainly big-endian // so we can safely use "buggy method"'s code msByte = peek( @myShortVar ) // rescued from endian bug on Intel lsByte = peek( @myShortVar + 1 ) // rescued from endian bug on Intel myShortVar = fn CFSwapInt16BigToHost( myShortVar ) // restore previous byte order print msByte, lsByte
print "fix 3", dim as Str255 tempString defstr long tempString = hex$( myShortVar ) msByte = val&( mid$( tempString, tempString[0] - 4, 2 ) ) lsByte = val&( right$( tempString, 2 ) ) print msByte, lsByte
print "fix 4", msByte = myShortVar >> 8 lsByte = myShortVar and 0x00FF print msByte, lsByte
Byte order on disk: data
// string format on disk; endian safe print #fileNum, anything input #fileNum, anything // written via the FBtoC runtime as big-endian on disk // automatically swapped by the runtime to little-endian read on Intel write #fileNum, shortVar, longVar, singleVar, doubleVar, int64Var // endian safe read #fileNum, shortVar, longVar, singleVar, doubleVar, int64Var // endian safe write #fileNum, anyRecordVar // on disk, has endianness of writer host; potential endian bug read #fileNum, anyRecordVar // byte order on disk preserved in reader host memory; potential endian bug write file #fileNum, address, numBytes // on disk, has endianness of writer host; potential endian bug read file #fileNum, address, numBytes // byte order on disk preserved in reader host memory; potential endian bug
Byte order on disk: resources
Standard system-defined resource types (e.g. STR#, moov, MENU) are big-endian on disk. System-supplied 'resource flippers' automatically byte-swap on an Intel Mac, in both read and write directions, during any call to any call to the relevant Resource Manager functions. Standard resource types are thereby made to take on the endianness of the host, and all your resource management code should just work, unchanged, on Intel. (Inept coding on your part, though, could get the ResType wrong, so that you ask for a 'voom' resource).
Custom resources have a potential endian bug.
Swapping floating point values in an array
include "Subs FloatByteSwapping.incl" dim as single value(9) dim as long j, n // read big-endian array in one chunk from disk n = 10 read file #1, @value(0), n*sizeof( single ) // make it host-endian for j = 0 to n - 1 value(j) = fn SwapSingleBigToHost!( value(j) ) next // value array is now host-endian, ready for use //... // make it big-endian again for j = 0 to n - 1 value(j) = fn SwapSingleHostToBig!( value(j) ) next // write big-endian array in one chunk to disk write file #1, @value(0), n*sizeof( single )SwapDoubleBigToHost#() and SwapDoubleHostToBig#() are available for swapping doubles similarly.
See also:
Universal Binary Programming Guidelines
Swapping Bytes
Byte-Order Utilities Reference