From: Justin C. <mi...@ce...> - 2007-07-12 23:09:24
|
On 12 Jul 2007 at 23:18, Fabio Napoleoni wrote: > First of all, hi to everyone because this is my first message. > > I think that I've found a bug, or maybe I'just think wrong. Before I > sumbit a bug report i ask in this list. > > Here is the code: > > #include <stdio.h> > #include <string.h> > > #define BIG_STRING "qwertyuiopqwertyuiopqwertyuiopqwertyuiopqwertyuiop" > > int main() { > char buf[12]; > int written; > written =3D snprintf(buf, sizeof(buf), "%s", BIG_STRING); > printf("Content is: %s\nlength is %d\nwritten is %d\n", buf, > strlen(buf), written); > return 0; > } > > and here is the result: > > Content is: qwertyuiopqw=BF " > length is 15 > written is -1 > > Now from man snprintf I read: > > "The snprintf() and vsnprintf() functions will write at most size-1 of > the characters printed into the output string (the size'th character > then gets the terminating `\0'); if the return value is greater than > or equal to the size argument, the string was too short and some > of the printed characters were discarded. The output is always > null-terminated." > > Therefore the correct output should be: > > Content is: qwertyuiopq > length is 11 > written is -1 > > I've tried this code on my Asus Notebook with WindowsXP and the last, > just updated, mingw version. The result is the same on another PC with > Win2k and an older version of Mingw. > > Can anyone could explain me what's wrong? > > -- > Fabio Napoleoni > f.n...@gm... > I think the main "bug" is in your programme, not in mingw or the implementation of snprintf (which is presumably the Microsoft _snprintf, because mingw does not provide its own C run-time library implementation). According to the ISO C99 standard (clause 7.19.6.5), the output of snprintf is not always null-terminated. It is only null-terminated if the= 2nd argument is less than the length that the output string would have if it were not truncated. Thus, your programme has a bug, in the sense that you use printf with "%s" to output a string which is not null-terminated. You get garbage characters beyond the 12 which were stored in the buffer. This is precisely what you should expect to happen when the implementation of snprintf is standard-confirming. What is not standard-conforming is the return value of -1. Acclording to the the standard, the return value of snprintf should be length the output string would have if it were not truncated (in this case 50). This is not really a bug, but merely a non-conformance issue. The Microsoft C run-time library, which mingw uses, is not, and does not claim to be, standard-conforming. Hope that clarifies things. Justin |
From: Danny S. <dan...@cl...> - 2007-07-12 23:30:09
|
Keith Marshall Friday, 13 July 2007 11:01 a.m. > > On Thursday 12 July 2007 23:38, James Steward wrote: > > Microsoft doesn't seem to have an snprintf, I think MinGW header > > files might make _snprintf appear as snprintf. > > I believe that this analysis is correct. Microsoft doesn't provide > snprintf, but does provide _snprintf; _snprintf treats the length > argument differently to the way snprintf is supposed to, (I think the > behaviour we've seen on GNU/Linux is correct, per C99 > standard). Thus, > I am willing to entertain a bug report -- if we provide snprintf, we > should make it work correctly, per C99; we should not simply > map it to > a non-conforming Microsoft substitute. > Recently added __mingw_snprintf and __mingw_vsnprintf work correctly, per C99. The substitutes also handle long double floats and %ll format specifier 2007-06-29 Danny Smith <dan...@us...> * mingwex/gdtoa/mingw_snprintf.c: New file. * mingwex/Makefile.in (GDTOA_DISTFILES): Add mingw_snprintf.c. (GDTOA_OBJS): Add mingw_snprintf.o. They were added to libmingwex.a primarily to fix long double I/O problems in libstdc++ and libgfortran. They have not been exposed yet in user headers. But they are useful in own right, so perhaps they should be. Danny > Regards, > Keith. > > -------------------------------------------------------------- > ----------- > This SF.net email is sponsored by DB2 Express > Download DB2 Express C - the FREE version of DB2 express and take > control of your XML. No limits. Just data. Click to get it now. > http://sourceforge.net/powerbar/db2/ > _______________________________________________ > MinGW-users mailing list > Min...@li... > > You may change your MinGW Account Options or unsubscribe at: > https://lists.sourceforge.net/lists/listinfo/mingw-users > |
From: Greg C. <chi...@co...> - 2007-07-17 16:19:35
|
On 2007-07-12 23:30Z, Danny Smith wrote: > > Recently added __mingw_snprintf and __mingw_vsnprintf work correctly, > per C99. Thanks for this. I've tested it as follows, and it looks great. (1) My production code has unit tests to validate snprintf(), because msvcrt isn't the only runtime that gets it wrong (e.g., borland has its own errors). All those tests pass now that I've built libmingwex with CFLAGS='-DEXPORT_WEAK_SNPRINTF_ALIAS' and (as a temporary expedient) added extern "C" int __mingw_snprintf(char *s, size_t n, const char *fmt, ...); #define snprintf __mingw_snprintf to my code. I'm sure you have a much stronger testsuite already, but it never hurts to run a few more tests. (2) As for speed, we don't want another "pow() is too slow" controversy, so I ran this function a hundred times: void time0() { static char buf[100] = "zzzzzzzzzzzzz"; snprintf(buf, 12, "%11.6f", 1234.56789); } and found that __mingw_snprintf took 30% longer; and it took 60% longer for this more-precise variant: static char buf[100] = "zzzzzzzzzzzzzzzzzzzzz"; snprintf(buf, 20, "%19.14f", 1234.5678911111111); That seems to be an acceptable price to pay for correctness. OTOH, using a 'd' conversion: static char buf[100] = "zzzzzzzzzzzzzzzzzzzzz"; snprintf(buf, 20, "%19.14d", 1234.5678911111111); the new code ran in 40% less time than the msvcrt version. So I look forward to seeing this in an official release whenever you get around to it. If msvcrt's _snprintf() remains available with its underscore-prefixed name, then is there any reason not to make the C99-conformant libmingwex version the default when the standard name snprintf() is used? |
From: Luke D. <cod...@ho...> - 2007-07-13 12:16:36
|
> From: jam...@op...> To: min...@li...= > Date: Fri, 13 Jul 2007 09:33:30 +1000> Subject: Re: [Mingw-users] Strange= snprintf behaviour> > On Thu, 2007-07-12 at 16:09 -0700, Brian Dessent wro= te:> > > > The alternative of providing a non-broken snprintf() would mean>= > implementing an entire printf()-family replacement from scratch, which> = > is a non-trivial undertaking and would betray the whole "minimalist"> > a= djective in the project's name, since the whole point is to use what> > the= operating system provides, warts and all.> > Could we supply a thin wrappe= r? Something that uses the MS supplied> dirty _snprintf at the back end and= massage it's functionality into> something that more closely resembles snp= rintf? =20 I doubt it. In order to calculate the C99 return value, i.e. the amount of = buffer space required for formatting the entire string, you would have to p= arse and understand the entire format string anyway. A better alternative w= ould be to use the open source "trio" library (http://sourceforge.net/proje= cts/ctrio/). > Or a compiler warning when someone uses snprintf instead of _snprintf -> = that the supplied snprintf is not what it should be, but some alias to> _sn= printf that is NQR? =20 Do you have some example code for this? =20 Luke = |
From: Keith M. <kei...@us...> - 2007-07-13 20:51:11
|
On Friday 13 July 2007 13:16, Luke Dunstan wrote: > On Friday 13 July 2007 00:33, James Steward wrote: > > Could we supply a thin wrapper? Something that uses the MS > > supplied dirty _snprintf at the back end and massage it's > > functionality into something that more closely resembles snprintf? > > I doubt it. In order to calculate the C99 return value, i.e. the > amount of buffer space required for formatting the entire string, you > would have to parse and understand the entire format string anyway. No, you would not necessarily need to do this. It may be ugly, kludgy and inefficient, but with a little bit of lateral thinking: if( (tmp = fopen( "nul", "wb" )) != NULL ) { want = vfprintf( tmp, format, arglist ); close( tmp ); } within a vsnprintf() implementation, will identify the buffer length required. If `want' turns out to be less than the provided buffer length, then just go ahead and use vsprintf() to populate the return string; otherwise, allocate a sufficiently large temporary buffer, use vsprintf() to populate it, truncate and zero terminate it at the proper length, and memcpy() the result to the return string, before freeing the temporary buffer. In either case, return `want' as the function return value. Yeah. It isn't pretty, and can fail if the "nul" device can't be opened, or if there isn't enough heap memory free, but in general it does work. I'm sure Danny's implementation is much more elegant. Regards, Keith. |
From: <rr...@cs...> - 2007-07-13 14:00:32
|
Justin Cooke writes: >The Microsoft C run-time library, which mingw uses, is not, >and does not claim to be, standard-conforming. Microsoft C does claim to be standard-conforming, with the original C89 standard. It doesn't claim to be C99 conforming, but pretty much nothing does. In this case, snprintf() is defined by C99 and not the C89 standard. I don't think defining snprintf as a default alias for _snprintf is a good idea. Projects should explictly decide wether Microsoft's _snprintf() will work for them. Ross Ridge |
From: Keith M. <kei...@us...> - 2007-07-13 20:22:19
|
On Friday 13 July 2007 15:00, Ross Ridge wrote: > I don't think defining snprintf as a default alias for _snprintf is > a good idea. =A0Projects should explictly decide wether Microsoft's > _snprintf() will work for them. I tend to agree with this; software written to expect a C99 conforming=20 snprintf() cannot possibly work correctly with Microsoft's _snprintf(). Software calling snprintf(), and expecting _snprintf()'s behaviour, is=20 broken, IMO. Regards, Keith. |
From: Erik de C. L. <mle...@me...> - 2007-07-13 21:55:34
|
Keith Marshall wrote: > Software calling snprintf(), and expecting _snprintf()'s behaviour, is > broken, IMO. I agree, but that is not what people expect. People call snprintf() and due to MinGW having what I consider a bad #define, get _snprintf() which is not ISO C99 conformant. It would actually be better that people get a compiler warning saying that snprintf is no found. Erik -- ----------------------------------------------------------------- Erik de Castro Lopo ----------------------------------------------------------------- "A Microsoft employee talking about open source is a lot like a virgin talking about sex. They know it's out there and seems to be popular but until they try it for themselves they will never properly understand the attraction." -- Geoff Lane on Linux Today |
From: Danny S. <dan...@cl...> - 2007-07-13 22:50:43
|
Ross Ridge Saturday, 14 July 2007 2:01 a.m. > > Justin Cooke writes: > >The Microsoft C run-time library, which mingw uses, is not, > >and does not claim to be, standard-conforming. > > > I don't think defining snprintf as a default alias for _snprintf is > a good idea. Projects should explictly decide wether Microsoft's > _snprintf() will work for them. > OK, how about this in stdio.h? #ifdef __USE_MINGW_SNPRINTF /* Let compiler redirect call rather than preprocessor to allow use in libstdc++ */ int __cdecl __MINGW_NOTHROW snprintf(char *, size_t, const char *, ...) asm ("___mingw_snprintf"); int __cdecl __MINGW_NOTHROW vsnprintf (char *, size_t, const char *, __VALIST) asm ("___mingw_vsnprintf"); #elif defined (__USE_MSVCRT_SNPRINTF) #define _snprintf snprintf #define _snprintf vsnprintf #endif Danny > Ross Ridge |
From: Erik de C. L. <mle...@me...> - 2007-07-13 23:58:49
|
Danny Smith wrote: > OK, how about this in stdio.h? > > #ifdef __USE_MINGW_SNPRINTF > /* Let compiler redirect call rather than preprocessor to allow use in > libstdc++ */ > int __cdecl __MINGW_NOTHROW snprintf(char *, size_t, const char *, ...) > asm ("___mingw_snprintf"); > int __cdecl __MINGW_NOTHROW vsnprintf (char *, size_t, const char *, > __VALIST) asm ("___mingw_vsnprintf"); I'm not qualified to say if the above seems right, bit the stuff below seems very wrong. > #elif defined (__USE_MSVCRT_SNPRINTF) > #define _snprintf snprintf > #define _snprintf vsnprintf > #endif Anybody who is actually using microsoft;s _snprintf will now either get a compile error of a C99 conformant snprintf. I also thing that doing this: #define snprintf _snprintf is wrong because anyone expecting a C99 conformant snprintf now gets microsofts non-conformat version. Erik -- ----------------------------------------------------------------- Erik de Castro Lopo ----------------------------------------------------------------- "I'd crawl over an acre of 'Visual This++' and 'Integrated Development That' to get to gcc, Emacs, and gdb. Thank you." -- Vance Petree |
From: Keith M. <kei...@us...> - 2007-07-14 15:47:09
|
On Saturday 14 July 2007 00:58, Erik de Castro Lopo wrote: > > #ifdef __USE_MINGW_SNPRINTF > > /* Let compiler redirect call rather than preprocessor to allow use > > in libstdc++ =A0*/ > > int __cdecl __MINGW_NOTHROW snprintf(char *, size_t, const char *, > > ...) asm ("___mingw_snprintf"); > > int __cdecl __MINGW_NOTHROW vsnprintf (char *, size_t, const char > > *, __VALIST) asm ("___mingw_vsnprintf"); > > I'm not qualified to say if the above seems right, bit the stuff > below seems very wrong. > > > #elif defined (__USE_MSVCRT_SNPRINTF) > > #define _snprintf snprintf > > #define _snprintf vsnprintf > > #endif I guess that's a typo; the symbols do appear in reversed order, in each=20 of these latter defines. > Anybody who is actually using microsoft;s _snprintf will now either > get a compile error of a C99 conformant snprintf. > > I also thing that doing this: > > =A0 =A0#define snprintf _snprintf > > is wrong because anyone expecting a C99 conformant snprintf now gets > microsofts non-conformat version. But, when the defines are guarded by `#if defined __USE_MSVCRT_SNPRINTF'=20 that seems reasonable; any user who explicitly defines that symbol must=20 surely want the Microsoft non-conforming behaviour. My 2p: since IEEE 1003.1-2001 (aka POSIX) also demands C99 conformant=20 behaviour, those defines could perhaps be specified thus: #ifdef __USE_MSVCRT_SNPRINTF /* * User has explicitly declared that snprintf() and vsnprintf() should * behave Microsoft's way, rather be than ISO C99 or POSIX conformant. */ # define snprintf _snprintf # define vsnprintf _vsnprintf #elif defined _POSIX_SOURCE || defined __USE_MINGW_SNPRINTF /* * Do stuff to make snprintf() and vsnprintf() conform to ISO C99, * because POSIX expects it so, or the user has explicitly requested * that it be so. */ : : #endif With this construction, code proclaiming to be POSIX will automatically do the right thing, while any other code will produce a compiler error,=20 if snprintf() is called without explicitly specifying which of the two incompatible __USE_???_SNPRINTF behaviours is intended; IMO, this is the=20 best way to handle this sort of ambiguity. =46WIW, Danny's declarations for the __USE_MINGW_SNPRINTF case look rather= =20 mysterious to me too; I trust him, so I will take his word for it, that=20 they do the right thing, or at least that he will test them, before he commits anything. Regards, Keith. |
From: Erik de C. L. <mle...@me...> - 2007-07-14 21:38:00
|
Keith Marshall wrote: > But, when the defines are guarded by `#if defined __USE_MSVCRT_SNPRINTF' > that seems reasonable; any user who explicitly defines that symbol must > surely want the Microsoft non-conforming behaviour. Agreed. > #elif defined _POSIX_SOURCE || defined __USE_MINGW_SNPRINTF > /* > * Do stuff to make snprintf() and vsnprintf() conform to ISO C99, > * because POSIX expects it so, or the user has explicitly requested > * that it be so. > */ > : > : > #endif > > With this construction, code proclaiming to be POSIX will automatically > do the right thing, And I should get _POSIX_SOURCE if I do gcc -std=gnu99 shouldn't I? > while any other code will produce a compiler error, > if snprintf() is called without explicitly specifying which of the two > incompatible __USE_???_SNPRINTF behaviours is intended; IMO, this is the > best way to handle this sort of ambiguity. Yep, especially if -std=gnu99 turns on _POSIX_SOURCE. Cheers, Erik -- ----------------------------------------------------------------- Erik de Castro Lopo ----------------------------------------------------------------- "Perl - The only language that looks the same before and after RSA encryption." -- Keith Bostic |
From: Danny S. <dan...@cl...> - 2007-07-14 22:18:20
|
> > And I should get _POSIX_SOURCE if I do gcc -std=gnu99 shouldn't I? > No. try gcc -dM -E -std=gnu99 nul.c | grep _POSIX_SOURCE then try gcc -dM -E -std=c99 nul.c | grep __STDC_VERSION__ or gcc -dM -E -std=gnu99 nul.c | grep __STDC_VERSION__ Danny |
From: Erik de C. L. <mle...@me...> - 2007-07-14 23:22:45
|
Danny Smith wrote: > > > > And I should get _POSIX_SOURCE if I do gcc -std=gnu99 shouldn't I? > > > > No. I'm not sure how to do it, but it would be nice if people who specified -std=c99 or -std=gnu99 got an ISO C99 compliant snprintf. I'll let the compiler experts figure out how to do that :-). Erik -- ----------------------------------------------------------------- Erik de Castro Lopo ----------------------------------------------------------------- "The fury with which untenable beliefs are defended is inversely proportional to their defensibility." -- Richard Dawkins |
From: Keith M. <kei...@us...> - 2007-07-15 14:54:20
|
On Sunday 15 July 2007 00:22, Erik de Castro Lopo wrote: > > > And I should get _POSIX_SOURCE if I do gcc -std=gnu99 shouldn't > > > I? > > > > No. > > I'm not sure how to do it, but it would be nice if people > who specified -std=c99 or -std=gnu99 got an ISO C99 compliant > snprintf. Which is exactly what you will get, with Danny's proposed solution, due to appropriate symbol exposure based on __STDC_VERSION__, which *is* defined, by the preprocessor, when you specify either of those options. OTOH _POSIX_SOURCE (or _POSIX_C_SOURCE as IEEE 1003.1-2001 would have us use today, deprecating _POSIX_SOURCE), should *never* be defined by the compiler; it is *your* responsibility to define it, when you write code which you intend to be POSIX conformant: http://www.opengroup.org/onlinepubs/009695399/functions/xsh_chap02_02.html Since MinGW targets a non-POSIX host, it is inappropriate for MinGW headers to completely honour the spirit of _POSIX_C_SOURCE; it would be wrong to define symbols required by POSIX, when the underlying platform lacks the capability to support them. However, while I do share Danny's concern about proliferating bug reports relating to lack of support for POSIX features, (which we get anyway), my own personal view is that we *should* make *sparing* use of _POSIX_C_SOURCE, (and also its older cousin, _POSIX_SOURCE), within MinGW headers, where it may be appropriate, and the case of snprintf() is a case in point. However, those who would port POSIX applications to Woe32, (of whom I am one), and who use MinGW as their compiler of choice, do have a responsibility to recognise the limitations: defining _POSIX_C_SOURCE does not magically turn Woe32 into a POSIX conforming system, and MinGW cannot treat it as such; if defining _POSIX_C_SOURCE doesn't make function bar() work, then it is *not* a bug in MinGW -- it indicates a requirement to reimplement function bar() in a Woe32 supported manner, and if the user wants the functionality, he or she needs to work out how to do that. OTOH, if I do define _POSIX_C_SOURCE, and then I call snprintf() and I still get MSVCRT's non-POSIX behaviour, then I think I *could* justifiably call that a bug; a POSIX-ly correct implementation *is* available, so it should have been chosen over the non-conforming MSVCRT variant. Still just my 2p. Regards, Keith. |
From: Danny S. <dan...@cl...> - 2007-07-14 18:18:52
|
Keith Marshall Sunday, 15 July 2007 3:47 a.m. > > But, when the defines are guarded by `#if defined > __USE_MSVCRT_SNPRINTF' > that seems reasonable; any user who explicitly defines that > symbol must > surely want the Microsoft non-conforming behaviour. > > My 2p: since IEEE 1003.1-2001 (aka POSIX) also demands C99 conformant > behaviour, those defines could perhaps be specified thus: > > #ifdef __USE_MSVCRT_SNPRINTF > /* > * User has explicitly declared that snprintf() and vsnprintf() should > * behave Microsoft's way, rather be than ISO C99 or POSIX conformant. > */ > # define snprintf _snprintf > # define vsnprintf _vsnprintf > > #elif defined _POSIX_SOURCE || defined __USE_MINGW_SNPRINTF > /* > * Do stuff to make snprintf() and vsnprintf() conform to ISO C99, > * because POSIX expects it so, or the user has explicitly requested > * that it be so. > */ > : > : > #endif > This is what I meant and what I actually tested: #if defined (__USE_MSVCRT_SNPRINTF) #define snprintf _snprintf #define snprintf _vsnprintf #elif defined (__USE_MINGW_SNPRINTF) \ || (defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) int __cdecl __MINGW_NOTHROW snprintf(char *, size_t, const char *, ...) asm ("___mingwsnprintf"); int __cdecl __MINGW_NOTHROW vsnprintf (char *, size_t, const char *, __VALIST) asm ("___mingw_vsnprintf"); #endif I used the asm redirection approach to provide long double IO support for libgfortran and libstdc++. The relavant testcase all pass. I world rather use __STDC_VERSION__ >= 199901L rather than _POSIX_SOURCE because 1) the former is defined by compile option --std=c99 2) mingw does not generally attempt to be POSIX compliant; it does attempt to be ISO c99 compliant. I don't want to start seeing bug reports like: "hey I defined _POSIX_SOURCE. POSIX function foo worked but POSIX function bar was not defined. Danny |
From: Keith M. <kei...@us...> - 2007-07-14 22:36:46
|
On Saturday 14 July 2007 19:18, Danny Smith wrote: > I used the asm redirection approach to provide long double IO support > for libgfortran =A0and libstdc++. =A0The relavant testcase all pass. I don't doubt it; I'd simply not encountered this syntax before :-) > I world rather use __STDC_VERSION__ >=3D 199901L rather than > _POSIX_SOURCE because > > 1) the former is defined by compile option --std=3Dc99 > 2) mingw does not generally attempt to be POSIX compliant; it does > attempt to be ISO c99 compliant. =46air enough. However... > I don't want to start seeing bug reports like: "hey I defined > _POSIX_SOURCE. POSIX function foo worked but POSIX function bar was > not defined.=20 There is code out there, which defines _POSIX_SOURCE without necessarily=20 requiring --std=3Dc99. This isn't a magic bullet, which is expected to=20 miraculously make POSIX functions appear on non-POSIX platforms; it is=20 simply a hint to the compiler that, in case of ambiguity, POSIX=20 semantics should prevail. I wouldn't want to see such bug reports either, but it could be useful=20 to quietly support this proper usage of _POSIX_SOURCE, in addition to=20 __STDC_VERSION__, maybe with a clarifying comment regarding such proper=20 usage, particularly emphasising what it shouldn't be expected to do. Regards, Keith. |
From: Greg C. <chi...@co...> - 2007-08-20 13:35:06
|
On 2007-07-14 18:18Z, Danny Smith wrote: > > This is what I meant and what I actually tested: Using all the latest MinGW tarballs, [v]snprintf() still forwards to msvcrt's _[v]snprintf(). To prevent this patch from being lost, would you like me to put it into the tracker? > #if defined (__USE_MSVCRT_SNPRINTF) > #define snprintf _snprintf > #define snprintf _vsnprintf > #elif defined (__USE_MINGW_SNPRINTF) \ > || (defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) > int __cdecl __MINGW_NOTHROW snprintf(char *, size_t, const char *, ...) > asm ("___mingwsnprintf"); > int __cdecl __MINGW_NOTHROW vsnprintf (char *, size_t, const char *, > __VALIST) asm ("___mingw_vsnprintf"); > #endif Here are two little changes that shouldn't be controversial: - #define snprintf _vsnprintf + #define vsnprintf _vsnprintf - asm ("___mingwsnprintf"); + asm ("___mingw_snprintf"); Here's one further suggestion. By default, neither of the macros __USE_MINGW_SNPRINTF __USE_MSVCRT_SNPRINTF would be predefined, so the behavior would be '--std=c99': use the conforming implementation otherwise (e.g., for C++): no [v]snprintf() at all and I think it would be better to use the conforming implementation unless there's a good reason not to; one way to achieve that is to add this at the top of the above patch: + #if !defined (__NO_ISOCEXT) + #define __USE_MINGW_SNPRINTF + #endif > I used the asm redirection approach to provide long double IO support > for libgfortran and libstdc++. The relavant testcase all pass. > > I world rather use __STDC_VERSION__ >= 199901L rather than _POSIX_SOURCE > because > > 1) the former is defined by compile option --std=c99 > 2) mingw does not generally attempt to be POSIX compliant; it does > attempt to be ISO c99 compliant. > I don't want to start seeing bug reports like: "hey I defined > _POSIX_SOURCE. POSIX function foo worked > but POSIX function bar was not defined. In a followup message on 2007-07-15T14:54Z, Keith presented a counterargument for doing, in effect, this: #elif defined (__USE_MINGW_SNPRINTF) \ + || defined (_POSIX_SOURCE) || defined (_POSIX_C_SOURCE) \ and I don't have a really strong opinion either way. But I see no other suggestion made after that, and I'd just like to see this patch go into HEAD one way or another. |
From: Keith M. <kei...@us...> - 2007-08-22 14:01:04
Attachments:
stdio.h.diff
|
On Monday 20 August 2007 14:34, Greg Chicares wrote: > Here's one further suggestion. By default, neither of the macros > =A0 __USE_MINGW_SNPRINTF > =A0 __USE_MSVCRT_SNPRINTF > would be predefined, so the behavior would be > =A0 '--std=3Dc99': use the conforming implementation > =A0 otherwise (e.g., for C++): no [v]snprintf() at all That's not strictly true; there may be no prototype declared, but the=20 two functions are still provided in libmingwex.a. > and I think it would be better to use the conforming implementation I'm not sure about this; I wonder if it may not be better to remove the=20 existing implementations from libmingwex.a, so ensuring that there=20 really would be a link-time error, if [v]snprintf is used without=20 making any explicit behavioural choice. That way, any user who calls=20 [v]snprintf, expecting the old (broken) MSVCRT behaviour, would at=20 least be alerted to the issue, rather than maybe getting an unpleasant=20 surprise later. > unless there's a good reason not to; one way to achieve that is to > add this at the top of the above patch: > > + #if !defined (__NO_ISOCEXT) > + #define __USE_MINGW_SNPRINTF > + #endif Is this really a good way to do this? My working copy has the attached=20 patch in place. If I were to add such an extra define, it would make=20 __USE_MINGW_SNPRINTF, and all the checking for _POSIX_C_SOURCE, or for __STDC_VERSION__ effectively redundant; the logic would reduce to the equivalent of:-- #ifdef __USE_MSVCRT_SNPRINTF /* * Use the MSVCRT implementations. */ # define snprintf _snprintf # define vsnprintf _vsnprintf #else /* * Definitions to enable the MinGW enhanced [v]snprintf implementation. */ : #endif > I'd just like to see this patch go into HEAD one way or another. > To prevent this patch from being lost, would you like me to put it > into the tracker?=20 No, thanks. Unless anyone speaks out against it, within the next 48=20 hours, I'll commit, as per my working copy, and remove the existing=20 (broken) implementation. Regards, Keith. |
From: Greg C. <chi...@co...> - 2007-08-23 14:13:43
|
On 2007-08-22 14:00Z, Keith Marshall wrote: > > Unless anyone speaks out against it, within the next 48 > hours, I'll commit, as per my working copy, and remove the existing > (broken) implementation. I applied the 'stdio.h.diff' patch from your email to fresh 4.2.1-dw2 and 4.2.1-sjlj installations here, and it seemed to cause C++ problems unless __USE_MINGW_SNPRINTF is defined explicitly. I see a related problem with the (different) patch in my earlier email. /tmp[0]$cat hello.cpp #include <iostream> #include <ostream> int main() { std::cout << "Hello" << std::endl; } /tmp[0]$/MinGW-20070814/bin/g++-dw2 -D__USE_MINGW_SNPRINTF hello.cpp /tmp[0]$./a Hello So far so good, but... /tmp[0]$/MinGW-20070814/bin/g++-dw2 hello.cpp In file included from c:\cygwin\mingw-20070814\bin\../lib/gcc/mingw32/4.2.1-dw2/include/c++/mingw32/bits/c++locale.h:49, from c:\cygwin\mingw-20070814\bin\../lib/gcc/mingw32/4.2.1-dw2/include/c++/iosfwd:45, from c:\cygwin\mingw-20070814\bin\../lib/gcc/mingw32/4.2.1-dw2/include/c++/ios:43, from c:\cygwin\mingw-20070814\bin\../lib/gcc/mingw32/4.2.1-dw2/include/c++/ostream:45, from c:\cygwin\mingw-20070814\bin\../lib/gcc/mingw32/4.2.1-dw2/include/c++/iostream:45, from hello.cpp:1: c:\cygwin\mingw-20070814\bin\../lib/gcc/mingw32/4.2.1-dw2/include/c++/cstdio:170: error: '::snprintf' has not been declared c:\cygwin\mingw-20070814\bin\../lib/gcc/mingw32/4.2.1-dw2/include/c++/cstdio:173: error: '::vsnprintf' has not been declared c:\cygwin\mingw-20070814\bin\../lib/gcc/mingw32/4.2.1-dw2/include/c++/cstdio:181: error: '__gnu_cxx::snprintf' has not been declared c:\cygwin\mingw-20070814\bin\../lib/gcc/mingw32/4.2.1-dw2/include/c++/cstdio:184: error: '__gnu_cxx::vsnprintf' has not been declared Explicitly defining __USE_MSVCRT_SNPRINTF: /tmp[1]$/MinGW-20070814/bin/g++-dw2 -D__USE_MSVCRT_SNPRINTF hello.cpp fails with the same set of diagnostics. I got similar results with that patch and sjlj--this worked: /MinGW-20070814-sjlj/bin/g++-sjlj -D__USE_MINGW_SNPRINTF hello.cpp while these failed: /MinGW-20070814-sjlj/bin/g++-sjlj -D__USE_MSVCRT_SNPRINTF hello.cpp /MinGW-20070814-sjlj/bin/g++-sjlj hello.cpp as above. A similar problem arises, only in the explicit -D__USE_MSVCRT_SNPRINTF case, with the patch in my 2007-08-20T13:34Z email. Do these various __USE_MSVCRT_SNPRINTF efforts still seem worthwhile, now that we've seen that it's harder than it looked at first? The purpose is apparently to accommodate anyone who wants C99 function snprintf() with non-C99 _snprintf() semantics: something that mingwex used to do, but msvc never did. Are we sure there's anyone who actually depends on that? I view this not as the substitution of one appropriate behavior for another, but as the correction of a known shortcoming that doesn't call for preservation of backward compatibility. |
From: Keith M. <kei...@us...> - 2007-08-23 18:22:07
|
On Thursday 23 August 2007 15:13, Greg Chicares wrote: > I applied the 'stdio.h.diff' patch from your email to fresh > 4.2.1-dw2 and 4.2.1-sjlj installations here, and it seemed to > cause C++ problems unless __USE_MINGW_SNPRINTF is defined > explicitly. Yikes! So, the libstdc++ headers are broken, if __USE_MINGW_SNPRINTF is not defined... > Explicitly defining __USE_MSVCRT_SNPRINTF: > > /tmp[1]$/MinGW-20070814/bin/g++-dw2 -D__USE_MSVCRT_SNPRINTF hello.cpp > > fails with the same set of [snipped] diagnostics. ...and they don't respect Danny's proposed __USE_MSVCRT_SNPRINTF at all. Over to you Danny, I think. Regards, Keith. |
From: Danny S. <dan...@cl...> - 2007-07-15 22:45:00
|
> On Sunday 15 July 2007 00:22, Erik de Castro Lopo wrote: > > > > And I should get _POSIX_SOURCE if I do gcc -std=gnu99 shouldn't > > > > I? > > > > > > No. > > > > I'm not sure how to do it, but it would be nice if people > > who specified -std=c99 or -std=gnu99 got an ISO C99 compliant > > snprintf. > > Which is exactly what you will get, with Danny's proposed > solution, due > to appropriate symbol exposure based on __STDC_VERSION__, which *is* > defined, by the preprocessor, when you specify either of > those options. > I just tried this: gcc -dM -E -posix nul.c | grep _POSIX_ #define _POSIX_SOURCE 1 So there's no problem with using a predefined _POSIX_SOURCE_ based on compiler switch. Danny |
From: Danny S. <dan...@cl...> - 2007-07-17 21:16:48
|
Greg Chicares Wednesday, 18 July 2007 4:19 a.m. > On 2007-07-12 23:30Z, Danny Smith wrote: > > > > Recently added __mingw_snprintf and __mingw_vsnprintf work > correctly, > > per C99. > > Thanks for this. I've tested it as follows, and it looks great. > > (1) My production code has unit tests to validate snprintf(), > because msvcrt isn't the only runtime that gets it wrong (e.g., > borland has its own errors). All those tests pass now that I've > built libmingwex with CFLAGS='-DEXPORT_WEAK_SNPRINTF_ALIAS' and > (as a temporary expedient) added Weak alias support 'seems' to work most times, but I would not count on it. The PE_COFF characteristics for the weak symbol are not set correctly in object file, so it is bound to fail wih MS linker. > extern "C" int __mingw_snprintf(char *s, size_t n, const > char *fmt, ...); > #define snprintf __mingw_snprintf > to my code. I'm sure you have a much stronger testsuite already, > but it never hurts to run a few more tests. > > (2) As for speed, we don't want another "pow() is too slow" > controversy, so I ran this function a hundred times: > void time0() > { > static char buf[100] = "zzzzzzzzzzzzz"; > snprintf(buf, 12, "%11.6f", 1234.56789); > } > and found that __mingw_snprintf took 30% longer; and it took > 60% longer for this more-precise variant: > static char buf[100] = "zzzzzzzzzzzzzzzzzzzzz"; > snprintf(buf, 20, "%19.14f", 1234.5678911111111); Thanks for that. I observed similar hit from using the gdtoa float conversion routine. > That seems to be an acceptable price to pay for correctness. > OTOH, using a 'd' conversion: > static char buf[100] = "zzzzzzzzzzzzzzzzzzzzz"; > snprintf(buf, 20, "%19.14d", 1234.5678911111111); > the new code ran in 40% less time than the msvcrt version. > > So I look forward to seeing this in an official release whenever > you get around to it. If msvcrt's _snprintf() remains available > with its underscore-prefixed name, then is there any reason not > to make the C99-conformant libmingwex version the default when > the standard name snprintf() is used? > IMHO, no. Danny > -------------------------------------------------------------- > ----------- > This SF.net email is sponsored by DB2 Express > Download DB2 Express C - the FREE version of DB2 express and take > control of your XML. No limits. Just data. Click to get it now. > http://sourceforge.net/powerbar/db2/ > _______________________________________________ > MinGW-users mailing list > Min...@li... > > You may change your MinGW Account Options or unsubscribe at: > https://lists.sourceforge.net/lists/listinfo/mingw-users > |
From: James S. <jam...@op...> - 2007-08-21 05:02:24
|
> Greg Chicares <chi...@co...> wrote: > In a followup message on 2007-07-15T14:54Z, Keith presented a > counterargument for doing, in effect, this: > > #elif defined (__USE_MINGW_SNPRINTF) \ > + || defined (_POSIX_SOURCE) || defined (_POSIX_C_SOURCE) \ Is it worth alerting folks when the non MSVC is being used, incase they didn't expect to get something different? Like a; #warning "Using MinGW snprintf" ? Regards, James. |
From: Greg C. <chi...@co...> - 2007-08-21 17:24:20
|
On 2007-08-21 05:02Z, James Steward wrote: >> Greg Chicares <chi...@co...> wrote: >> In a followup message on 2007-07-15T14:54Z, Keith presented a >> counterargument for doing, in effect, this: >> >> #elif defined (__USE_MINGW_SNPRINTF) \ >> + || defined (_POSIX_SOURCE) || defined (_POSIX_C_SOURCE) \ > > Is it worth alerting folks when the non MSVC is being used, incase > they didn't expect to get something different? Like a; > > #warning "Using MinGW snprintf" > > ? Only underscore-prefixed versions of the snprintf functions are imported from the ms runtime; on my machine at least, /WINDOWS/SYSTEM32/MSVCRT.DLL doesn't even contain versions without the underscore, and msdn seems to document not snprintf() but only _snprintf(): http://msdn2.microsoft.com/en-us/library/2ts7cx93(vs.71).aspx So it's not that msvcrt has a non-conforming snprintf(); rather, it provides a nonstandard function with a different name and different semantics--which is still available as such even with this patch. As a MinGW extension, mingwex provides functions with the C99 names. Until this file: mingwex/gdtoa/mingw_snprintf.c was recently added, there was no conforming implementation at hand, so those functions just forwarded to _snprintf(). Now that there's a correct implementation, this patch would use it to provide C99 behavior for the C99 name--with this workaround: CPPFLAGS=-D__USE_MSVCRT_SNPRINTF for anyone who wants to call snprintf() and get _snprintf() behavior. My shop compiles with '-Werror', and I wouldn't want to have to devise a workaround to suppress a warning for correct behavior. There are very few #warnings in MinGW headers, and it looks like most of them predict fatal problems downstream that users would have to fix anyway. |