Also, if you're passing data between two processes (e.g. your code fork()d a child), you can be sure that the data format is going to match, no packing required. (still need to ensure alignment in memory though)
This is not necessarily true. Lots of systems support running 32-bit and 64-bit binaries simultaneously, and structs won't necessarily be portable between the two. Some versions of Mac OS X even supported running 32-bit PowerPC binaries (in an emulator, but supported directly by the OS) next to both 32-bit and 64-bit x86 binaries, so you could not only get size mismatches, but also endian mismatches.
This does not apply to simply forking, of course, but it does apply to the "two processes" case in general.
Oh yes, I was a bit unclear but I meant two processes (from the same binary) communicating.
Without that condition, you've got all the original problems, as listed. You can also have incompatibilities between compilers, or even compiler versions - e.g. gcc has ABI changes between some versions.
Depends on what system and context you're talking about. I'd assume it's rare on Linux where most things are built from source, but it's pretty common on e.g. Apple platforms where binary compatibility means 32-bit processes keep being supported for years, and they still need to IPC to various system services. I've seen one highly amusing bug in Apple's iOS frameworks where they didn't quite handle the 32->64 IPC case properly because of an implicit assumption that data types remained identical.
This does not apply to simply forking, of course, but it does apply to the "two processes" case in general.