This sounds like something memcpy would do already for you?
unsigned int x = in[0] + 512*in[1] + 512*512*in[2] + 512*512*512*in[3];
/* aka x = *(int*)in */
out[0] = x & 255; x>>=8;
out[1] = x & 255; x>>=8;
out[2] = x & 255; x>>=8;
out[3] = x & 255;
/* *not* aka *(int*)out = x */Although the Standard defines the behavior of signed-to-unsigned conversion in a way that would yield the same bit pattern as a two's-complement signed number, some compilers will issue warnings if a signed value is implicitly coerced to unsigned. Adding the extra 18 forms would generally require nothing more than defining an extra 24 macros, which seems like a reasonable way to prevent such issues.
Far less bloat than would be needed for a compiler to recognize and optimize any meaningful fraction of the ways people might write code to work around the lack of portably-specified library functions.