Binary Compatibility of C Object Files Across Compilers

ccompiler

I understand that C++ compilers are not compatible with each other. However, I was unable to find anything on this topic for C in particular. I know that the C standard leaves a lot of room for compilers to implement things however they see fit: for example, the size and alignment of most (all?) data types is implementation-defined save for some minimal guarantees. Therefore, two compilers (or two versions of the same compiler) can disagree on numerous details.

Am I correct in thinking that there's no guarantee that two object files compiled with different compilers will actually link properly? For example, the size of pointers could be 32 bits in one object file and 64 bits in the other. But if that's so, why are C libraries sometimes distributed in precompiled form? Is there an expectation that I'll use the same compiler they did (e.g. gcc), or some de facto standard being used to ensure binary compatibility? And how do other languages with a Foreign Language Interface ensure things will line up properly when linking with C object files?

Best Answer

The general answer is no, C language compilers are not compatible with each other. The C language standard does not define any kind of binary interoperability, and most compiler writers don't even try.

I need to qualify that. The objects emitted by a C compiler have to be linked with runtime libraries to produce either an executable or a runtime linkable library. Although the visible functions provided by the C runtime library should be compatible, there will also be non-visible functions that are unique to the implementation and prevent interoperability.

This lack of compatibility also extends to different versions of the same compiler. In general, programs and libraries compiled with older and newer versions of a compiler cannot be linked together, and those compiled with MSVC cannot be linked with those compiled by GCC.

There is a specific and very useful exception. Every platform provides a dynamic linking ABI (Application Binary Interface) and any program in any language that can conform to that ABI is compatible. Therefore it is generally possible to build a DLL (on Windows) with MSVC (or something else) and call it from a program compiled by a different version of MSVC or by GCC and vice versa.

There are two other ABIs on Windows: COM and .NET assemblies, and they span a wide range of languages. So interoperability is definitely possible, but compatible they are not.


The degree of incompatibility can easily be seen by comparing the linker maps. For GNU use ld -M, for MSVC use link /map. Study the two generated files. Both will have names in them that you recognise, such as printf and main, although (depending on options) the names are likely to be mangled in various ways. They will also have names that are completely different, many of which you won't recognise. In order for object files produced by different compilers to be compatible they have to agree on all those names, and they never do. Not even different versions of the same compiler can always do that.

Related Topic