Discussion:
[Mingw-w64-public] how to printf() 64-bit integer in 64-bit compiler in strict ISO mode with all warnings enabled?
Lev Serebryakov
2017-06-21 20:41:45 UTC
Permalink
Here are problem, which was discussed in the past, but without this
"all warnings enabled" part.

So, I need to printf() uint64_t in my project, which is built in strict
ISO C11 mode and with all warnings enabled.

If I try to use "%llu" I get warning that "unknown conversion type
character 'l' in format". If I use "%I64u" I get "ISO C does not support
the 'I64' ms_printf length modifier" warning.

PRIu64 doesn't work, of course, because it is "I64u".

How to write portable code without warnings?

And bonus question: how to print size_t, as %zu isn't supported either!
--
// Black Lion AKA Lev Serebryakov
Lev Serebryakov
2017-06-21 22:30:03 UTC
Permalink
Hello Lev,
Post by Lev Serebryakov
So, I need to printf() uint64_t in my project, which is built in strict
ISO C11 mode and with all warnings enabled.
If I try to use "%llu" I get warning that "unknown conversion type
character 'l' in format". If I use "%I64u" I get "ISO C does not support
the 'I64' ms_printf length modifier" warning.
And, yes, I have _POSIX_C_SOURCE defined on compiler's command line.
--
Best regards,
Lev mailto:***@serebryakov.spb.ru
Liu Hao
2017-06-22 01:46:33 UTC
Permalink
Post by Lev Serebryakov
Hello Lev,
Post by Lev Serebryakov
So, I need to printf() uint64_t in my project, which is built in strict
ISO C11 mode and with all warnings enabled.
If I try to use "%llu" I get warning that "unknown conversion type
character 'l' in format". If I use "%I64u" I get "ISO C does not support
the 'I64' ms_printf length modifier" warning.
And, yes, I have _POSIX_C_SOURCE defined on compiler's command line.
In order to get C99 conforming `*printf()` functions you have to
`#define __USE_MINGW_ANSI_STDIO 1` before inclusion of any standard
headers. One preferable way to achieve that is adding
`-D__USE_MINGW_ANSI_STDIO` into your CPPFLAGS.
--
Best regards,
LH_Mouse
s***@optusnet.com.au
2017-06-22 02:53:24 UTC
Permalink
-----Original Message-----
From: Liu Hao
Sent: Thursday, June 22, 2017 11:46 AM
To: mingw-w64-***@lists.sourceforge.net
Subject: Re: [Mingw-w64-public] how to printf() 64-bit integer in 64-bit
compiler in strict ISO mode with all warnings enabled?
Post by Lev Serebryakov
So, I need to printf() uint64_t in my project, which is built in strict
ISO C11 mode and with all warnings enabled.
If I try to use "%llu" I get warning that "unknown conversion type
character 'l' in format". If I use "%I64u" I get "ISO C does not support
the 'I64' ms_printf length modifier" warning.
And, yes, I have _POSIX_C_SOURCE defined on compiler's command line.
In order to get C99 conforming `*printf()` functions you have to `#define
__USE_MINGW_ANSI_STDIO 1` before inclusion of any standard headers. One
preferable way to achieve that is adding `-D__USE_MINGW_ANSI_STDIO` into
your CPPFLAGS.
This is what I invariably do, too.

However, in a recent post to a gmp mailing list (
https://gmplib.org/list-archives/gmp-bugs/2017-May/004162.html ), Keith
Marshall discouraged this, warning that it was *not* guaranteed to continue
to work into the future.

Here's the relevant bit (from that post) of what he had to say:

[--quote--]

I would also point out that, as a "__USE_*" feature test, users should *not*
define "__USE_MINGW_ANSI_STDIO" themselves; the correct way to enable it is
to enable any of the "__STRICT_ANSI__" standards options, or to stipulate
"_GNU_SOURCE", "_POSIX_C_SOURCE", or "_XOPEN_SOURCE" feature dependencies,
(the latter two with an associated version stipulation), any of which will
cause the MinGW runtime headers to enable "__USE_MINGW_ANSI_STDIO"
implicitly. You may get away with an explicit definition today, but I will
offer no guarantee that a future MinGW Runtime release will not override any
such definition, just as GNU's glibc headers do for their "__USE_*" feature
tests.

[--end quote--]

AFAIK Keith's allegiance is with mpfr.org, and I don't know how/if those
remarks relate to mingw-w64.

Any thoughts on that ?

Cheers,
Rob
Lev Serebryakov
2017-06-22 11:39:37 UTC
Permalink
Hello Liu,
Post by Liu Hao
Post by Lev Serebryakov
Post by Lev Serebryakov
So, I need to printf() uint64_t in my project, which is built in strict
ISO C11 mode and with all warnings enabled.
If I try to use "%llu" I get warning that "unknown conversion type
character 'l' in format". If I use "%I64u" I get "ISO C does not support
the 'I64' ms_printf length modifier" warning.
And, yes, I have _POSIX_C_SOURCE defined on compiler's command line.
In order to get C99 conforming `*printf()` functions you have to
`#define __USE_MINGW_ANSI_STDIO 1` before inclusion of any standard
headers. One preferable way to achieve that is adding
`-D__USE_MINGW_ANSI_STDIO` into your CPPFLAGS.
I've started to prepare minimal example for my problem and found one more
ingridient for my problem:" custom function with prinrf attribute. These
defines work for system *printf() family, but not for custom ones.

Here is very simple example of exactly my problem:

==============
#include <stdio.h>
#include <stdint.h>
#include <stdarg.h>

__attribute__ ((format (printf, 1, 2)))
void myprintf(const char *fmt, ...) {
va_list args;
va_start(args, fmt);
vprintf(fmt, args);
va_end(args);
}

int main(int argc, char *argv[]) {
uint64_t i = 10;
size_t s = 20;
(void)argc; (void)argv;
printf("%llu %zu\n", i, s);
myprintf("%llu %zu\n", i, s);
return 0;
}
==============
***@lion MINGW64 ~
$ gcc -D_POSIX_C_SOURCE=1 test.c

***@lion MINGW64 ~
$ ./a.exe
10 20
10 20

***@lion MINGW64 ~
$ gcc -D_POSIX_C_SOURCE=1 -std=c11 -Wall -Wextra -Wpedantic -Wformat=2 -Werror test.c
test.c: In function 'main':
test.c:17:15: error: unknown conversion type character 'l' in format [-Werror=format=]
myprintf("%llu %zu\n", i, s);
^
test.c:17:19: error: unknown conversion type character 'z' in format [-Werror=format=]
myprintf("%llu %zu\n", i, s);
^
test.c:17:12: error: too many arguments for format [-Werror=format-extra-args]
myprintf("%llu %zu\n", i, s);
^~~~~~~~~~~~
cc1.exe: all warnings being treated as errors

***@lion MINGW64 ~
$
--
Best regards,
Lev mailto:***@serebryakov.spb.ru
Lev Serebryakov
2017-06-22 12:19:42 UTC
Permalink
Well, your issue is "(format (printf, ... )". First use __printf, or
even better __printf__. Nevertheless the printf formatter is
representing the default print-formatter style. That is obviously on
Windows not the gnu-ish variant.
But you can explicit tell it, that you want to use a different
variant. Eg "__attribute__((__format__ (gnu_printf,..." for gnu-style.
Oh, thank you! It is not obvious, as it is not mentioned in GCC
documentation :)
--
// Black Lion AKA Lev Serebryakov
Lev Serebryakov
2017-06-22 16:41:25 UTC
Permalink
Be welcome. Well, actually gcc has one paragraph about this. You can
find it in gcc's extend.texi. It is part of the item 'format
I've looked at GCC online documentation :) It mention ms_* but not
gnu_* for mingw target.

One more question: looks like PRId64 and others from <inttypes.h> are
always "I64", am I right? Is it possible to get ISO-standard defines for
int64_t/uint64_t?

I've checked and both _POSIX_C_SOURCE=1 and __USE_MINGW_ANSI_STDIO=1
don't affect this define.
--
// Black Lion AKA Lev Serebryakov
Lev Serebryakov
2017-06-25 13:11:06 UTC
Permalink
Hello Kai,
Post by Lev Serebryakov
I've checked and both _POSIX_C_SOURCE=1 and __USE_MINGW_ANSI_STDIO=1
don't affect this define.
It should, at least the latter one should show effect. Of course you
need to define it before including inttypes.h
Very simple test case:

a.c ======
#include <inttypes.h>
PRId64
==========

$ gcc -D_POSIX_C_SOURCE=1 -D__USE_MINGW_ANSI_STDIO=1 -E a.c
[skipped a lot]
# 1 "C:/msys64/mingw64/x86_64-w64-mingw32/include/_mingw_print_pop.h" 1 3
# 300 "C:/msys64/mingw64/x86_64-w64-mingw32/include/inttypes.h" 2 3
# 2 "a.c" 2
"I64d"
$
--
Best regards,
Lev mailto:***@serebryakov.spb.ru
Liu Hao
2017-06-25 17:39:09 UTC
Permalink
Post by Lev Serebryakov
Hello Kai,
Post by Lev Serebryakov
I've checked and both _POSIX_C_SOURCE=1 and __USE_MINGW_ANSI_STDIO=1
don't affect this define.
It should, at least the latter one should show effect. Of course you
need to define it before including inttypes.h
a.c ======
#include <inttypes.h>
PRId64
==========
$ gcc -D_POSIX_C_SOURCE=1 -D__USE_MINGW_ANSI_STDIO=1 -E a.c
[skipped a lot]
# 1 "C:/msys64/mingw64/x86_64-w64-mingw32/include/_mingw_print_pop.h" 1 3
# 300 "C:/msys64/mingw64/x86_64-w64-mingw32/include/inttypes.h" 2 3
# 2 "a.c" 2
"I64d"
$
Confirmed.

This is because the following `#if` on line 8 in <_mingw_print_pop.h>
prevents the preprocessor from restoring those macros if neither
<stdio.h> or <wchar.h> is included before <inttypes.h>:

```c
#if defined(__USE_MINGW_ANSI_STDIO) && (defined(_INC_STDIO) ||
defined(_WSTDIO_DEFINED)) && ((__USE_MINGW_ANSI_STDIO + 0) != 0)
```
--
Best regards,
LH_Mouse
Lev Serebryakov
2017-06-26 11:04:00 UTC
Permalink
Post by Liu Hao
Post by Lev Serebryakov
Post by Lev Serebryakov
I've checked and both _POSIX_C_SOURCE=1 and __USE_MINGW_ANSI_STDIO=1
don't affect this define.
It should, at least the latter one should show effect. Of course you
need to define it before including inttypes.h
a.c ======
#include <inttypes.h>
PRId64
==========
$ gcc -D_POSIX_C_SOURCE=1 -D__USE_MINGW_ANSI_STDIO=1 -E a.c
[skipped a lot]
# 1 "C:/msys64/mingw64/x86_64-w64-mingw32/include/_mingw_print_pop.h" 1 3
# 300 "C:/msys64/mingw64/x86_64-w64-mingw32/include/inttypes.h" 2 3
# 2 "a.c" 2
"I64d"
$
Confirmed.
This is because the following `#if` on line 8 in <_mingw_print_pop.h>
prevents the preprocessor from restoring those macros if neither
Problem is, here could be files which don't need nor <stdio.h> neither
<wchar.t>, but need formatting macros. For example, if custom logging
subsystem used (it is my case) or it is file defining a lot of messages
but no any code at all. I think, it is minor bug in mingw64. Should I
file it?
--
// Black Lion AKA Lev Serebryakov
Liu Hao
2017-06-26 15:57:49 UTC
Permalink
Post by Lev Serebryakov
Post by Liu Hao
Post by Lev Serebryakov
Post by Lev Serebryakov
I've checked and both _POSIX_C_SOURCE=1 and __USE_MINGW_ANSI_STDIO=1
don't affect this define.
It should, at least the latter one should show effect. Of course you
need to define it before including inttypes.h
a.c ======
#include <inttypes.h>
PRId64
==========
$ gcc -D_POSIX_C_SOURCE=1 -D__USE_MINGW_ANSI_STDIO=1 -E a.c
[skipped a lot]
# 1 "C:/msys64/mingw64/x86_64-w64-mingw32/include/_mingw_print_pop.h" 1 3
# 300 "C:/msys64/mingw64/x86_64-w64-mingw32/include/inttypes.h" 2 3
# 2 "a.c" 2
"I64d"
$
Confirmed.
This is because the following `#if` on line 8 in <_mingw_print_pop.h>
prevents the preprocessor from restoring those macros if neither
Problem is, here could be files which don't need nor <stdio.h> neither
<wchar.t>, but need formatting macros. For example, if custom logging
subsystem used (it is my case) or it is file defining a lot of messages
but no any code at all. I think, it is minor bug in mingw64. Should I
file it?
Yes please go ahead.
--
Best regards,
LH_Mouse
Liu Hao
2017-06-27 16:06:03 UTC
Permalink
Patch attached.
--
Best regards,
ltpmouse


From 35656690a3eb69ac5694de27081e9213df2eec79 Mon Sep 17 00:00:00 2001
From: Liu Hao <***@126.com>
Date: Tue, 27 Jun 2017 23:57:39 +0800
Subject: [PATCH] mingw-w64-headers/crt/_mingw_print_pop.h: Do not check for
_INC_STDIO or _WSTDIO_DEFINED any more, as there is no such check in
<_mingw_print_push.h>.

Signed-off-by: Liu Hao <***@126.com>
---
mingw-w64-headers/crt/_mingw_print_pop.h | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/mingw-w64-headers/crt/_mingw_print_pop.h
b/mingw-w64-headers/crt/_mingw_print_pop.h
index 046b6203..ac524618 100644
--- a/mingw-w64-headers/crt/_mingw_print_pop.h
+++ b/mingw-w64-headers/crt/_mingw_print_pop.h
@@ -5,7 +5,7 @@
*/

/* Define __mingw_<printf> macros. */
-#if defined(__USE_MINGW_ANSI_STDIO) && (defined(_INC_STDIO) ||
defined(_WSTDIO_DEFINED)) && ((__USE_MINGW_ANSI_STDIO + 0) != 0)
+#if defined(__USE_MINGW_ANSI_STDIO) && ((__USE_MINGW_ANSI_STDIO + 0) != 0)

/* Redefine to GNU specific PRI... and SCN... macros. */
#if defined(_INTTYPES_H_) && defined(PRId64)
@@ -133,4 +133,4 @@
#endif /* _WIN64 */
#endif /* defined(_INTTYPES_H_) && defined(PRId64) */

-#endif /* defined(__USE_MINGW_ANSI_STDIO) && defined(_INC_STDIO) &&
__USE_MINGW_ANSI_STDIO != 0 */
+#endif /* defined(__USE_MINGW_ANSI_STDIO) && __USE_MINGW_ANSI_STDIO != 0 */
--
2.13.0
Loading...