If you're going to use the preprocessor, this is the time to use it. There are different solutions but I believe that you can solve this in a clean way.
The way I usually solve it is I first create a header that does a platform and compiler detection, eg:
#define LIB_PLATFORM_WIN32 (1)
#define LIB_PLATFORM_LINUX (2)
#if defined(WIN32)
#define LIB_PLATFORM LIB_PLATFORM_WIN32
#elif defined(LINUX)
#define LIB_PLATFORM LIB_PLATFORM_LINUX
#endif
Now you've got your platform; you can then just use your own defines throughout your code.
For example, if you want a compiler independent 64bit integer you could use this
#if LIB_COMPILER == LIB_COMPILER_MSVC
#define int64 __int64
#define uint64 unsigned __int64
#else
#define int64 long long
#define uint64 unsigned long long
#endif
If you keep it well structured you shouldnt have a problem keeping it clean and sane. :)
You could also use typedefs, but that might bring other problems if you want to overload a type later in your application.