Note that very often function parameters and local variables are not stored in RAM, and only exist in registers. This is especially true for 32-bit ARMs. If you use a smaller explicit-size type like unsigned char, int8_t, or int16_t, the compiler may have to add unnecessary AND instructions to ensure the passed register contains a value representable by that type.
Technically, C does nowadays provide types like int_fastN_t and uint_fastN_t for N = 8, 16, 32, and 64, where the type is at least that size, possibly larger, whatever is most efficient for the target processor, exactly for this purpose (local variables and static inline function parameters). For example, on x86-64 on Linux, gcc uses 8-bit uint_fast8_t and int_fast8_t, but 64-bit for the larger types.
The one oddball trick I have sometimes used is to fill in the string buffer backwards, from right to left.
For example:
char *prepend_uint(char *p, unsigned int u)
{
do {
*(--p) = '0' + (u % 10);
u /= 10;
} while (u);
return p;
}
char *prepend_block(char *p, const void *s, const int n)
{
memcpy(p - n, s, n);
return p - n;
}
char *prepend_reverse(char *p, const char *s)
{
while (*s) {
*(--p) = *(s++);
}
return p;
}
Let's say you want to construct string No accidents for num days, and you have a buffer with room for say 32 characters, char buffer[32];. You would use the above functions using e.g.
char *p = buffer + sizeof buffer;
*(--p) = '\0'; /* End-of-string marker */
p = prepend_reverse(p, "syad ");
p = prepend_uint(num);
p = prepend_reverse(p, " rof stnedicca oN");
or, equivalently,
char *p = buffer + sizeof buffer;
*(--p) = '\0';
p = prepend_block(p, " days", 4);
p = prepend_uint(num);
p = prepend_block("No accidents for ", 13);
and in both cases, you would have the desired string starting at p .
To see exactly why this would be useful, one would need to look at the machine code: this compiles to very tight little code. Right-aligning fixed-width fields, and alternate versions for architectures where ROM/Flash memory access is special, is easy to implement.
When filling buffers in the normal order, you can convert numbers to strings in reverse (swapped right-to-left), append any left padding, reverse the string, and finally append any right padding.