Binary (unformatted) files are 100% compatible among all fortran compilers and all c compilers on all hardware platforms. You just have to know how to read them! Some conventions will make this trivial as opposed to a hardship. I regularly exchange data among Sun, Alpha, Athlon, Intel, G4, IBM SP, you name it, and have figured out how to make it work seamlessly -- mostly by using netCDF.
ALWAYS use direct access for binary output. This avoids currupting the file with headers on each record and allows you to read the data in arbitrary chunks, not just the chunks of the writing program. With sequential access, you not only need to know how big the data array is, but how it was written. Also, sharing between c and fortran causes real headaches with sequential access.
Direct access is awkward for saving mixed data to a single file. That's probably a bad idea anyway -- how are you going to remember what's in the file? Use a self-describing format like ascii or netCDF for mixed-data files. Or use separate files for each data type with filenames that tell you what's in them.
Note that on some compilers (eg Dec Fortran) you need to specify the record length is measured in bytes (eg -assume byterecl). Thus (in f77):
program write integer m,n, sizeofreal parameter (m=10, n=10, sizeofreal=4) real x(m,n) c insert some code to fill x c open direct access unformatted file with records sized for the whole array open (unit=1, $ file='out.r4', $ form='unformatted', $ access='direct', $ recl=m*n*sizeofreal) c write the whole thing as one record write (1,rec=1) x end program read integer m,n parameter (m=10, n=10) real x(m,n) c open direct access unformatted file with records sized for a single row c note how we can read in the data differently from how it was written. c You just need to make recl the smallest thing you will read and adjust c your read statements accordingly open (unit=1, $ file='out.r4', $ form='unformatted', $ access='direct', $ recl=m*4) c read in each row as a single record do j = 1, n read (1,rec=j) (x(i,j), i=1,m) end do end
The above will work when run on any two machines that have the same byte order convention. Intel/AMD and Alpha (Dec/Compaq/HP) are so-called "little-endian". Mac, Sun, HP (risc), SGI, and most everything else are "big endian". Big endian used to be standard, but now with the rise of intel beowulf clusters, you get a lot of litte-endian. Two solutions:
Use a compiler flag to force big endian (or little endian if you prefer) so all your platforms work the same. This only works if you control both writing and reading. Eg, in Dec fortran, this is -convert big_endian
Detect the byte order of your machine and swap as needed. Again, you need to know what convention your input file is to know if it is different from the machine you are reading from (usually easy to figure out since the data will be garbage if you have it wrong). The following routines will effect a byte swap for 2-byte integers and 4-byte reals:
subroutine endian(litend) c checks if this is a little endian machine c returns litend=.true. if it is, litend=.false. if not integer*1 j(2) integer*2 i equivalence (i,j) logical litend i = 1 if (j(1).eq.1) then litend = .true. else litend = .false. end if end subroutine byteswapi2(k) c does a byteswap on integer2 number integer*1 ii(2), jj(2) integer*2 i, j, k equivalence (i,ii) equivalence (j,jj) i = k jj(1) = ii(2) jj(2) = ii(1) k = j end subroutine byteswapr4(r) c does a byteswap on real*4 number integer*1 ii(4), jj(4) real*4 r, s, t equivalence (s,ii) equivalence (t,jj) s = r jj(1) = ii(4) jj(2) = ii(3) jj(3) = ii(2) jj(4) = ii(1) r = t end
When using NAGware f95, you need the -dusty flag to compile the above, so there is evidently something non-standard or obsolete about it. There is probably a more elegant solution, but this works.
If someone does send you a sequential-access file, corrupting the data with garbage headers, you'll need the code they used to write the file and hope your machine uses the same record headers. You can still do the byte swapping. If record headers are different, open as direct access with recl=4 and experiment to find out how many bytes (records on read) you need to skip over to get to the data. Tell them never to do that again.
The best solution, by far, is to use a platform-independent file format like netCDF or HDF -- or even gzipped ascii (use system calls to gunzip on the fly).
Back to the OS X page