This is an automated email from the ASF dual-hosted git repository. acassis pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/nuttx.git
commit 13d1f6c2a79b0ec09490b73fc70f75ac67ca5eb6 Author: Marco Casaroli <[email protected]> AuthorDate: Thu Nov 5 12:06:49 2026 +0100 libs/libc/stream: Add an option for 64-bit integers in printf(). On a 32-bit CPU each integer conversion goes through 64-bit division, even for %d. With LIBC_PRINTF_LONG_LONG off, the digit loop uses long. A value longer than long is read at its size, and printf() prints "?". The option is on in the Default and Full profiles. In the Minimal profile it stays on with SYSLOG_TIMESTAMP or FS_PROCFS, because the timestamps of syslog and the times in /proc print with %jd. It has no effect where long has 64 bits. Part of https://github.com/apache/nuttx/issues/21467 Assisted-by: Claude Code:claude-opus-5-5 Signed-off-by: Marco Casaroli <[email protected]> --- libs/libc/stdio/Kconfig | 13 +++++++++++++ libs/libc/stream/lib_libvsprintf.c | 26 +++++++++++++++++++++++--- libs/libc/stream/lib_ultoa_invert.c | 2 +- libs/libc/stream/lib_ultoa_invert.h | 19 ++++++++++++++++++- 4 files changed, 55 insertions(+), 5 deletions(-) diff --git a/libs/libc/stdio/Kconfig b/libs/libc/stdio/Kconfig index f2e526df1e9..a80eaa47a01 100644 --- a/libs/libc/stdio/Kconfig +++ b/libs/libc/stdio/Kconfig @@ -81,6 +81,19 @@ config LIBC_PRINTF_FULL endchoice # printf profile +config LIBC_PRINTF_LONG_LONG + bool "Enable 64-bit integers in printf on a 32-bit CPU" + default !LIBC_PRINTF_MINIMAL || SYSLOG_TIMESTAMP || FS_PROCFS + ---help--- + Enables the output of %lld, %llu, %llx, %jd and the others where + long long is longer than long. Without it, printf() needs no 64-bit + division. It reads the argument and prints "?". This option has + no effect on a CPU where long has 64 bits. + + The Minimal profile leaves it on with SYSLOG_TIMESTAMP or FS_PROCFS, + because the timestamps of syslog and the times in /proc print with + %jd. + config LIBC_FLOATINGPOINT bool "Enable floating point in printf" default LIBC_PRINTF_FULL || (!DEFAULT_SMALL && ARCH_FPU && !LIBC_PRINTF_MINIMAL) diff --git a/libs/libc/stream/lib_libvsprintf.c b/libs/libc/stream/lib_libvsprintf.c index d2b560572a6..617216ea2d1 100644 --- a/libs/libc/stream/lib_libvsprintf.c +++ b/libs/libc/stream/lib_libvsprintf.c @@ -97,6 +97,14 @@ #define FL_FLTEXP 0x4000 #define FL_FLTFIX 0x8000 +/* A value longer than long has output only with this option */ + +#if defined(CONFIG_LIBC_PRINTF_LONG_LONG) || ULLONG_MAX == ULONG_MAX +# define HAVE_LONG_LONG_OUTPUT 1 +#else +# define HAVE_LONG_LONG_OUTPUT 0 +#endif + /* L, as ll, means a long double in a floating point conversion */ #ifdef CONFIG_HAVE_LONG_DOUBLE @@ -843,6 +851,7 @@ flt_oper: if (c == 'a') { +put_unavailable: pnt = "?"; size = 1; goto str_lpad; @@ -1153,6 +1162,7 @@ flt_oper: } } +put_unavailable: pnt = "?"; size = 1; goto str_lpad; @@ -1313,7 +1323,7 @@ str_lpad: if (c == 'd' || c == 'i') { - long long x; + ultoa_int_t x; if ((flags & FL_LONG) != 0 && (flags & FL_REPD_TYPE) != 0) { @@ -1327,6 +1337,11 @@ str_lpad: { x = va_arg(ap, long long); } + + if (!HAVE_LONG_LONG_OUTPUT) + { + goto put_unavailable; + } } else if ((flags & FL_LONG) != 0) @@ -1371,7 +1386,7 @@ str_lpad: flags &= ~(FL_NEGATIVE | FL_ALT); if (x < 0) { - x = -(unsigned long long)x; + x = -(ultoa_uint_t)x; flags |= FL_NEGATIVE; } @@ -1403,7 +1418,7 @@ str_lpad: else { int base; - unsigned long long x; + ultoa_uint_t x; if ((flags & FL_LONG) != 0 && (flags & FL_REPD_TYPE) != 0) { @@ -1417,6 +1432,11 @@ str_lpad: { x = va_arg(ap, unsigned long long); } + + if (!HAVE_LONG_LONG_OUTPUT) + { + goto put_unavailable; + } } else if ((flags & FL_LONG) != 0) diff --git a/libs/libc/stream/lib_ultoa_invert.c b/libs/libc/stream/lib_ultoa_invert.c index bf6898ecc33..b28fcf930f5 100644 --- a/libs/libc/stream/lib_ultoa_invert.c +++ b/libs/libc/stream/lib_ultoa_invert.c @@ -43,7 +43,7 @@ * Public Functions ****************************************************************************/ -FAR char *__ultoa_invert(unsigned long long val, FAR char *str, int base) +FAR char *__ultoa_invert(ultoa_uint_t val, FAR char *str, int base) { int upper = 0; diff --git a/libs/libc/stream/lib_ultoa_invert.h b/libs/libc/stream/lib_ultoa_invert.h index e3b04d19ac3..786711ecfd1 100644 --- a/libs/libc/stream/lib_ultoa_invert.h +++ b/libs/libc/stream/lib_ultoa_invert.h @@ -40,8 +40,11 @@ * Included Files ****************************************************************************/ +#include <nuttx/config.h> #include <nuttx/compiler.h> +#include <limits.h> + /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ @@ -51,12 +54,26 @@ #define XTOA_PREFIX 0x0100 /* Put prefix for octal or hex */ #define XTOA_UPPER 0x0200 /* Use upper case letters */ +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/* The integer that printf() can print */ + +#if defined(CONFIG_LIBC_PRINTF_LONG_LONG) || ULLONG_MAX == ULONG_MAX +typedef long long ultoa_int_t; +typedef unsigned long long ultoa_uint_t; +#else +typedef long ultoa_int_t; +typedef unsigned long ultoa_uint_t; +#endif + /**************************************************************************** * Public Function Prototypes ****************************************************************************/ /* Internal function for use from `printf'. */ -FAR char *__ultoa_invert(unsigned long long val, FAR char *str, int base); +FAR char *__ultoa_invert(ultoa_uint_t val, FAR char *str, int base); #endif /* __LIBS_LIBC_STREAM_LIB_ULTOA_INVERT_H */
