At the language level, there is no silver bullet. The best you can do is to stick to the language standard as closely as possible. Most compilers have options to issue warnings or errors if you take advantage of an extension that's specific to a particular compiler (with Visual C++, /Za
will disable non-standard language extensions). But this isn't perfect, as no compiler yet implements absolutely 100% of the standard, so you can still have portability problems even with strictly-compliant code.
Also be aware that lots of everyday code actually takes advantage of extensions or undefined- or compiler-defined behaviors, often without realizing it, so it might not be practical to compile in a fully standards-compliant mode.
You also have to be aware of things that the standards allow to be different. For example, types like int may be different sizes on different systems. Windows is LLP64, while most Unix-derived OSes are LP64.
At the system level, I don't know of a perfect way to make sure a programmer is not relying on something system-specific (e.g., <windows.h>
or <pthreads.h>
).
Your best bet is to make it simple for all developers to run test builds on all target platforms.