ti/sprintf.h
#include <ti/sprintf.h>
The OS comes with an implementation of ANSI C89 sprintf, which can reduce the size of a program by ~8 KiB. However, it is very limited in functionality. It does not support length modifiers, and it won’t accept long
or float
arguments.
boot_sprintf
The following type specifiers are supported %s %c %d %i %u %o %x %X %p %n
. The minimum field width *
, precision .*
, alongside -+#0
and the space flag are also supported. However, the precision .*
field is ignored for integers.
All length modifiers hh h l ll j z t L
and floating point specifiers %f %g %e %a
are not supported.
Additionally, each individual argument will write no more than 255 characters each. This means that any strings written with %s
will be truncated after 255 characters.
<ti/sprintf.h>
provides boot_sprintf, boot_snprintf, and boot_asprintf, in addition to boot_vsprintf, boot_vsnprintf, and boot_vasprintf which accept a va_list.
int boot_sprintf(char *restrict buffer, const char *restrict format, ...)
int boot_vsprintf(char *restrict buffer, const char *restrict format, va_list args)
int boot_snprintf(char *restrict buffer, size_t count, const char *restrict format, ...)
int boot_vsnprintf(char *restrict buffer, size_t count, const char *restrict format, va_list args)
int boot_asprintf(char **restrict p_buffer, const char *restrict format, ...)
int boot_vasprintf(char **restrict p_buffer, const char *restrict format, va_list args)
sprintf is traditionally “unsafe” because a maximum output length cannot be specified, which can cause buffer overflows. By writing to an unmapped memory address 0xE40000
, boot_sprintf can safely write up to ~786000 bytes which can then be used to determine the length of the output.
Replacing printf functions
To replace all other printf functions with the boot_sprintf functions, add the following line to the Makefile. More information here.
HAS_PRINTF = NO
boot_vsprintf
Because the OS does not provide vsprintf, boot_vsprintf is implemented by counting the number of arguments in the format string, and then copying the arguments from va_list onto the stack so they can be passed into boot_sprintf.
boot_asprintf
boot_asprintf functions similarly to asprintf. It will automatically allocate a buffer containing the output from boot_sprintf. The buffer shall be deallocated with free
. The returned buffer will be NULL
if an allocation or formatting error occurs.
boot_snprintf
boot_snprintf is similar to snprintf, except that it returns an empty string if the result of boot_sprintf won’t fit inside the buffer. Otherwise passing in boot_snprintf(NULL, 0, format, args)
can be used to query the length of the output without writing to a buffer.
The truncating behavior of C99 snprintf can be replicated with boot_asprintf
char buf[20];
char *temp;
boot_asprintf(&temp, format, ...);
if (temp != NULL) {
strncpy(buf, temp, sizeof(buf));
buf[sizeof(buf) - 1] = '\0'; // null terminate the end of the buffer
free(temp);
}
printf and fprintf
printf and fprintf can be replicated by using fputs
char output[50];
boot_snprintf(output, format, ...);
// fprintf(stdout, ...) == printf(...)
fputs(stdout, output);