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 */

Reply via email to