It is possible to write portable code if you stick to something that both compilers support such as perhaps pure ANSI C/C++ or whatever standards level / features they have in common.
You generally may want to code so that the code doesn't assume things like:
* 32 bit vs 64 bit architecture
* little endian vs big endian memory layout of data types
* sizeof or precision of -- short int, int, long int, double, float, char, et. al.
* consider not using / taking pointers to memory objects that aren't aligned according to the data type being accessed, e.g. don't store / reference 'doubles' or 'long int's aligned on 1 byte boundaries -- make sure doubles are aligned on even 8 byte multiple boundaries, longs are aligned on the same, et. al.
Many architectures benefit when you align accesses on dword or qword boundaries regardless of type stored.
* don't assume anything about the cache for instructions / data in use by the CPU.
* needless to say, self-modifying code is out.
* needless to say, avoid mixed C/assembler.
* don't call library functions that won't be present and compatible in features on all platforms .
* don't assume the compiler options will be identical, so expect to have a different makefile for each platform even if the source code is the same.
* don't assume the presence of a given threading model or memory protection model.
other than this kind of stuff, yeah, code is often portable given a recompile between the two.