This is why C is mostly portable with minimum effort unless you do hardware specific things, or use the variable to their limits. In that case you can always define fixed size types.
I don't get why people love to bash C. No language has an obligation to do please the programmer in its default modus operandi. Programming languages exist to interface hardware with humans, and C operates in the realm of the hardware, and that's perfectly OK for me.
C ABIs (of which there are many because the C standard doesn’t cover ABI) are full of legacy cruft, because they need to be stable and backwards-compatible more than they need to be sensible or efficient.
The C ABI can even vary depending on compiler flags, e.g. availability of AVX affects calling conventions. It’s not easy to be interoperable with this, especially when ABI-affecting compiler flags and macros may be set by an arbitrary build system, not even the C source code.