0

i was looking at this heap implementation, and i was wondering if it is necessary to implement heap for printf even if i'm calling setvbuf(stdout, NULL, _IONBF, 0) before calling printf.

i looked at how printf is implemented and it calls this function :

int 
_DEFUN (_VFPRINTF_R, (data, fp, fmt0, ap),
 struct _reent *data _AND
 FILE * fp _AND
 _CONST char *fmt0 _AND
 va_list ap)
{
 register char *fmt; /* format string */
 register int ch; /* character from fmt */
 register int n, m; /* handy integers (short term usage) */
 register char *cp; /* handy char pointer (short term usage) */
 register struct __siov *iovp;/* for PRINT macro */
 register int flags; /* flags as above */
 int ret; /* return value accumulator */
 int width; /* width from format (%8d), or 0 */
 int prec; /* precision from format (%.3d), or -1 */
 char sign; /* sign prefix (' ', '+', '-', or 0円) */
 char old_sign; /* saved value of sign when looping for vectors */
 int old_ch; /* saved value of ch when looping for vectors */
 char *format_anchor; /* start of format to process */
 wchar_t wc;
#ifdef FLOATING_POINT
 char *decimal_point = localeconv()->decimal_point;
 char softsign; /* temporary negative sign for floats */
#ifdef _NO_LONGDBL
 union { int i; double d; } _double_ = {0};
 #define _fpvalue (_double_.d)
#else
 union { int i; _LONG_DOUBLE ld; } _long_double_ = {0};
 #define _fpvalue (_long_double_.ld)
 int tmp; 
#endif
 int expt; /* integer value of exponent */
 int expsize = 0; /* character count for expstr */
 int ndig; /* actual number of digits returned by cvt */
 char expstr[7]; /* buffer for exponent string */
#endif
#ifndef _NO_LONGLONG
#define quad_t long long
#define u_quad_t unsigned long long
#else
#define quad_t long
#define u_quad_t u_long
#endif
 u_quad_t _uquad; /* integer arguments %[diouxX] */
 enum { OCT, DEC, HEX } base;/* base for [diouxX] conversion */
 int dprec; /* a copy of prec if [diouxX], 0 otherwise */
 int realsz; /* field size expanded by dprec */
 int size; /* size of converted field or string */
 char *xdigs = NULL; /* digits for [xX] conversion */
#define NIOV 8
 struct __suio uio; /* output information: summary */
 struct __siov iov[NIOV];/* ... and individual io vectors */
 char buf[BUF]; /* space for %c, %[diouxX], %[eEfgG] */
 char ox[2]; /* space for 0x hex-prefix */
#ifdef __ALTIVEC__
 char vec_sep; /* vector separator char */
 int vec_print_count; /* number of vector chunks remaining */
 vec_16_byte_union vec_tmp;
#endif /* __ALTIVEC__ */ 
 mbstate_t state; /* mbtowc calls from library must not change state */
 /*
 * Choose PADSIZE to trade efficiency vs. size. If larger printf
 * fields occur frequently, increase PADSIZE and make the initialisers
 * below longer.
 */
#define PADSIZE 16 /* pad chunk size */
 static _CONST char blanks[PADSIZE] =
 {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '};
 static _CONST char zeroes[PADSIZE] =
 {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'};
 /*
 * BEWARE, these `goto error' on error, and PAD uses `n'.
 */
#define PRINT(ptr, len) { \
 iovp->iov_base = (ptr); \
 iovp->iov_len = (len); \
 uio.uio_resid += (len); \
 iovp++; \
 if (++uio.uio_iovcnt >= NIOV) { \
 if (__sprint_r(data, fp, &uio)) \
 goto error; \
 iovp = iov; \
 } \
}
asked Sep 27, 2025 at 21:39
3
  • OT: does the register keyword really do anything anymore? I read that with optimizations On and today's architecture, the compiler does a pretty good job of registering everything anyway. I think register was born in an era of scarce registers and CPUs . . . and hence it made sense then, rt? Commented Sep 27, 2025 at 22:37
  • 1
    @gregspears "today's architecture" -- I would expect some situations that could still benefit from the register specifier, e.g., old platforms with old compilers, immature microcontroller architectures with immature compiler support, compilers with weak optimization, etc. Commented Sep 27, 2025 at 23:11
  • check documentation for your standard library. if the documentation says it is necessary, then it is. Commented Sep 28, 2025 at 2:04

1 Answer 1

4

You need to forget many things you remember from "normal" computers when developing for MCUs.

and i was wondering if it is necessary to implement heap for printf even if i'm calling setvbuf(stdout, NULL, _IONBF, 0) before calling printf

  1. On STM32 (and other embedded targets using newlib-nano or newlib-nano + ARM toolchain), setvbuf(stdout, NULL, _IONBF, 0) does not really do anything useful in most cases:
  • There is no real stdout buffer

  • In the nano/newlib builds for STM32, stdout is usually tied to a very thin wrapper (like _write() implemented by you, sending characters to SWO, UART, or semihosting).

  1. With STM32 + newlib-nano, printf does not use the heap for integer/strings, but does use the heap when you enable floating-point formats (%f, %e, %g) via -u _printf_float. The float path calls _dtoa_r which allocates via _malloc_r and ultimately your _sbrk.

I would suggest writing your own implementation of the conversion functions:

struct _reent;
char * _dtoa_r(struct _reent *r, double d, int mode, int ndigits,
 int *decpt, int *sign, char **rve)
{
 (void)r; (void)mode; (void)rve;
 static char buf[64]; // not reentrant
 // TODO: convert d into buf, set *decpt and *sign
 return buf;
}
void _freedtoa(char *p) { (void)p; }
// Optional if you ever use %Lf
char * _ldtoa_r(struct _reent *r, long double d, int mode, int ndigits,
 int *decpt, int *sign, char **rve)
{
 return _dtoa_r(r, (double)d, mode, ndigits, decpt, sign, rve);
}
answered Sep 28, 2025 at 10:21
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.