This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of New status.

4216. num_put::do_put and void pointers

Section: 28.3.4.3.3.3 [facet.num.put.virtuals] Status: New Submitter: Nikolas Klauser Opened: 2025-02-26 Last modified: 2025-03-02

Priority: Not Prioritized

View other active issues in [facet.num.put.virtuals].

View all other issues in [facet.num.put.virtuals].

View all issues with New status.

Discussion:

The num_put::do_put overloads are defined in terms of printf. However, it is not clear what the intended behaviour of pointers is.

While the num_put wording makes a quite clear statement that it should be whatever printf("%p", ptr) would be, num_get is entirely silent on which function should be used. This makes it entirely unclear whether round-tripping is supposed to work. It's also not clear whether num_put was just simple to specify via printf or whether the intent was that the output matches in all cases. Round-tripping between num_put and num_get was broken in libc++ until recently. However, to fix that, the output of num_put::do_put no longer matches the libc's printf in all cases. libstdc++ had this behaviour since at least two decades, indicating that nobody seems to have a problem with num_put::do_put and printf having different results in some rare cases.

Proposed resolution:

This wording is relative to N5001.

  1. Modify 28.3.4.3.3.3 [facet.num.put.virtuals] as indicated:

    iter_type do_put(iter_type out, ios_base& str, char_type fill, long val) const;
    iter_type do_put(iter_type out, ios_base& str, char_type fill, long long val) const;
    iter_type do_put(iter_type out, ios_base& str, char_type fill, unsigned long val) const;
    iter_type do_put(iter_type out, ios_base& str, char_type fill, unsigned long long val) const;
    iter_type do_put(iter_type out, ios_base& str, char_type fill, double val) const;
    iter_type do_put(iter_type out, ios_base& str, char_type fill, long double val) const;
    iter_type do_put(iter_type out, ios_base& str, char_type fill, const void* val) const;
    

    -1- Effects: […]

    -2- The details of this operation occur in several stages: […]

    -3- Detailed descriptions of each stage follow.

    -4- Returns: out.

    Stage 1: The first action of stage 1 is to determine a conversion specifier. […]

    For conversion from void* the specifier is %p.

    The representations at the end of stage 1 consists of the char's that would be printed by a call of printf(s, val) where s is the conversion specifier determined above, except that any implementation-defined behavior of printf may be different from a call to printf.