On Monday 17 November 2025 17:13:56 Martin Storsjö wrote:
> On Sat, 25 Oct 2025, Pali Rohár wrote:
> 
> > Format %Z takes pointer to ANSI_STRING or UNICODE_STRING based on the
> > wideness of format.
> > 
> > In this mingw-w64 implementation (same as in UCRT) the uppercase format %Z
> > has the same default wideness as uppercase format %S when no h, l or w
> > modifier is specified.
> > 
> > Format %Z is supported by crtdll, msvcrt and UCRT libraries. There are some
> > differences between individual CRT versions regarding the wide wprintf(%lZ),
> > narrow printf(%Z/%lZ) and whether nul chars in ANSI_STRING are accepted by
> > wprintf or not. In mingw-w64 for compatibility reasons are accepted.
> 
> The last sentence, "In mingw-w64 for compatibility reasons are accepted."
> seems like it is missing something, in order to make sense.

Ah, right, there is missing "they" (nul chars). Should be "they are accepted".

> > diff --git a/mingw-w64-crt/stdio/mingw_pformat.c 
> > b/mingw-w64-crt/stdio/mingw_pformat.c
> > index bdc7eba2a573..ded916c9a2bc 100644
> > --- a/mingw-w64-crt/stdio/mingw_pformat.c
> > +++ b/mingw-w64-crt/stdio/mingw_pformat.c
> > @@ -66,6 +66,7 @@
> > #include <limits.h>
> > #include <locale.h>
> > #include <wchar.h>
> > +#include <ntdef.h>
> > 
> > #ifdef __ENABLE_DFP
> > #ifndef __STDC_WANT_DEC_FP__
> > @@ -2558,6 +2559,64 @@ __pformat (int flags, void *dest, int max, const 
> > APICHAR *fmt, va_list argv)
> >                */
> >               __pformat_puts( va_arg( argv, char * ), &stream );
> >             goto format_scan;
> > +
> > +          case 'Z':
> > +            /*
> > +             * The logic for `%Z` length modifier is quite complicated.
> > +             *
> > +             * for printf:
> > +             * `%Z`  - UNICODE_STRING for UCRT; ANSI_STRING for 
> > crtdll,msvcrt10,msvcrt,msvcr80-msvcr120
> > +             * `%hZ` - ANSI_STRING
> > +             * `%lZ` - UNICODE_STRING for UCRT; ANSI_STRING for 
> > crtdll,msvcrt10,msvcrt,msvcr80-msvcr120
> > +             * `%wZ` - UNICODE_STRING
> > +             *
> > +             * for wprintf:
> > +             * `%Z`  - ANSI_STRING
> > +             * `%hZ` - ANSI_STRING
> > +             * `%lZ` - UNICODE_STRING for UCRT; ANSI_STRING for 
> > crtdll,msvcrt10,msvcrt,msvcr80-msvcr120
> > +             * `%wZ` - UNICODE_STRING
> > +             *
> > +             * There are some other changes between versions regarding nul 
> > chars.
> > +             * - msvcrt since Vista, msvcr80+ and UCRT do not accept nul 
> > chars in ANSI_STRING for wprintf. They stop at nul char and returns -1.
> > +             * - crtdll, msvcrt10 and msvcrt before Vista accept nul char 
> > in ANSI_STRING for wprintf, but ANSI_STRING content after nul char is 
> > discarded.
> 
> This explanation doesn't feel like it makes sense to me. If it accepts the
> nul char, the wouldn't it also proceed after that? So do you say that it
> includes the single nul char in the output, but nothing after it? While the
> logical thing would be to either stop at the nul (not outputting it) or
> include everything?

I used term "accept" whether wprintf will continue or immediately
returns -1. I think that this was the main confusing here.

I will try to explain it a bit differently.

msvcrt since Vista, msvcr80+ and UCRT: If ANSI_STRING contains nul
char then wprintf() function process and prints all characters from
ANSI_STRING before the nul char. nul char is not printed. wprintf()
stops processing at the nul char and immediately returns -1. It even
does not process next %fmt format arguments.

crtdll, msvcrt10 and msvcrt before Vista: If ANSI_STRING contains nul
char then wprintf() trims the nul char and everything after it in
ANSI_STRING and prints just trimmed content. After that it continues to
next %fmt format arguments.

> > +             * - ANSI_STRING for printf, and UNICODE_STRING for both 
> > printf and wprintf works fine in all versions.

--> meaning: If the *_STRING contains nul char then the *printf function
             really prints it, and also prints everything after nul char.

> > +             *
> > +             * This mingw-w64 implementation uses UCRT behavior of length 
> > modifiers.
> > +             * And for compatibility with older msvcrt versions, it 
> > accepts also
> > +             * nul chars in ANSI_STRING for wprintf and discard content 
> > after
> > +             * nul char (like msvcrt).
> 
> Same thing in this explanation here.
> 
> Or should the first case be UNICODE_STRING in both of these explanations?
> Accept nul in UNICODE_STRING, terminate at nul in ANSI_STRING?
> 
> // Martin

Better explanation:

This mingw-w64 implementation uses:
- UCRT behavior of _format_ length modifiers in both printf and wprintf
- crtdll/msvcrt10/pre-Vista-msvcrt behavior of printing of ANSI_STRING with nul 
bytes in wprintf


_______________________________________________
Mingw-w64-public mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/mingw-w64-public

Reply via email to