20

I have successfully installed MinGW on a Windows 7 32bit machine, and have tried to compile a simple program using either the command line or the MinGW console.

The code has an intentional error in a printf statement:

#include <stdio.h>
#include <stdlib.h>
int main( void )
{
    printf("%d\n" , 3.14 ) ;
return 0 ;
}

The command gcc -Wall hello.c gives a correct warning: hello.c:7:2: warning: format '%d' expects argument of type 'int'...

But the command gcc -std=c99 -Wall hello.c doesn't give any warning.

Both create an executable a.exe ( that runs and gives the same result ).

(Interestingly a command gcc -std=gnu99 -Wall hello.c gives the warning.)

I don't know if this is a bug, or did the installation go wrong somehow, but both seem unlikely since the compiler works and successfully compiled a larger project( but the same warning of course omitted when using -std=c99 ).

I must be missing some information.

(ps: If someone has a new MinGW install, please test this.)

gcc version 4.8.1 (GCC)

Update 1:

Defining _GNU_SOURCE before including stdio.h removes the warning even with gcc -Wall hello.c.

Update 2( might be less relevant ):

Compiling

 printf("%lf\n" , 3.14 ) ;

-std=c99 flag outputs: 0.000000

-std=gnu99 outputs: 3.140000

And compiling:

 printf("%f\n" , 3.14 ) ;

-std=gnu99 and -std=c99 output: 3.140000

Update 3:

Functions that seem to be affected are: printf, fprintf, snprintf, sprintf.

2501
  • 25,460
  • 4
  • 47
  • 87
  • What version? `gcc --version` – ooga Dec 08 '14 at 17:51
  • 2
    I get the same result (also 4.8.1). Someone should tell the developers because this seems like a bug to me. – ooga Dec 08 '14 at 17:55
  • What if you use -Wformat explicitly? – Lars Ljung Dec 08 '14 at 17:57
  • How about `-Wformat`? – Shafik Yaghmour Dec 08 '14 at 17:58
  • @LarsLjung @ Shafik Yaghmour No difference. I tried them all. – 2501 Dec 08 '14 at 18:01
  • What happens if you `#define _GNU_SOURCE` before including `` but compile as ISO C? Maybe the declarations for `printf` differ for GNU- and non-GNU C (and some annotation to the declaration is necessary to trigger the warning). Just a guess, though. – mafso Dec 08 '14 at 18:01
  • @mafso Well that is interesting. The warning disappeared with that define and `gcc -Wall hello.c`. – 2501 Dec 08 '14 at 18:03
  • Can you preprocess the various combinations and grep for the `printf` declarations? – mafso Dec 08 '14 at 18:09
  • @mafso What do you mean? Every error that does and doesn't show? Every printf warning is completely ignored. – 2501 Dec 08 '14 at 18:10
  • I wonder if `printf` is declared the same in `` or maybe has some `__attribute__ (__format__ ...)` in one case but not the other. My GCC man page says, that `-Wformat` ambiguates certain `printf` versions (ISO C, with POSIX extensions, with GNU extensions, ...) for the warnings. I don't know how GCC knows which version is used, but maybe the declarations differ (or some macros are in action). `-E` runs only the preprocessor, `-E -dM` gives a list of defined macros. `(printf)(...)` would suppress macro expansion in case it is defined. – mafso Dec 08 '14 at 18:30
  • 1
    @mafso `static __inline__ __attribute__((__cdecl__)) __attribute__ ((__nothrow__)) int printf (const char *__format, ...) {`... – 2501 Dec 08 '14 at 18:35
  • For all combinations of `-std=[c|gnu][89]` with and without `#define _GNU_SOURCE`? And I'm quite surprised about a static function btw. – mafso Dec 08 '14 at 18:43
  • @mafso No warning from any -std=cXX and always a warning from -std=gnuXX. – 2501 Dec 08 '14 at 18:45
  • Also, if `printf("%lf\n" , 3.14 );` results in anything but 3.14, that's a bug. – The Paramagnetic Croissant Dec 08 '14 at 20:31
  • 1
    Actually mingw has more bugs and less features of Windows and new C and C++ standard supported compared to mingw64 and the development doesn't seem to progress much either http://en.wikipedia.org/wiki/MinGW#MinGW-w64 – phuclv Dec 09 '14 at 08:37
  • 2
    @LưuVĩnhPhúc Thank you for the suggestion. MinGW-w64 doesn't suffer from these issues. – 2501 Dec 09 '14 at 09:40

1 Answers1

16

The problem with the lack of warning when using the std=c99 option looks like it's because MinGW 4.8.1 preprocesses stdio.h a little different for the printf() family of functions when -std=c99 is used compared to when -std=gnu99 is used.

Note: I'm looking at MinGW 4.8.1 from TDM - I think other distributions might differ in these details.

MinGW has had some compatibility issues with formatting floating point values because of its historic reliance on msvcrt.dll for the C runtime and the fact that MSVC uses a 64-bit representation for long double while gcc uses a 96-bit (or 128-bit on x64) representation. See gcc: printf and long double leads to wrong output. [C - Type conversion messes up] for some details. More recent versions of MinGW have provided thier own implementation of the printf() family of functions (with a __mingw_ prefix on the name) in libmingwex.a to solve those problems.

The header files _mingw.h and stdio.h configure whether or not the libmingwex.a implementations or the msvcrt.dll implementations will be used.

It appears that if ANSI compliance is requested, MinGW will use the libmingwex.a implementations (there are a number of other ways to get this configuration too - look at the headers for details). Wiring up a user call to printf() to the __mingw_printf() implementation in libmingwex.a is done by stdio.h defining a static inline implementation of printf() that is a thin wrapper around a call to __mingw_vfprintf(). Apparently the -Wformat doesn't get applied to versions of printf() family functions that the compiler doesn't believe to be part of the library (a reasonable assumption - the compiler doesn't really know anything about those functions). This problem can be fixed by applying the appropriate function attribute (for example: __attribute__ ((format (printf, 1, 2)))) to the static inline wrapper functions.

The other problem you found, where printf("%lf\n", 3.14) prints 0.000000 when using std=c99, looks to be a bug in the libmingwex.a implementation of __mingw_vfprintf(). It seems that __mingw_vfprintf() mistakenly interprets "%lf" to mean the argument is a long double. I'm not too surprised by that - I always have to look up whether %lf means double or long double.

Community
  • 1
  • 1
Michael Burr
  • 333,147
  • 50
  • 533
  • 760
  • Very well. I'll quote from the C standard, since I can see you're used to that. ["f,F A double argument representing a floating-point number ..."](http://www.iso-9899.info/n1570.html#7.21.6.1p8) – autistic Apr 18 '15 at 09:20
  • It's not really possible to pass a `float` to `printf()` because an argument of that type is promoted to `double`. I suppose that`"%lf"` and `"%f"` are equivalent so format strings with them can 'echo' their use in `scanf()`. But I'm not sure what these recent comments are about - the answer says that it appears that `__mingw_vfprintf()` might be mistakenly treating `"%lf"` as using a `long double` argument since it apparently produces different output for `"%lf"` and `"%f"` specifications. It doesn't say that `"%lf"` should be used with a `long double` type. – Michael Burr Apr 18 '15 at 17:39
  • The `l` in `%lf` is explicitly ignored - `%f` alone covers the use of `double` and `float` (the latter being down-converted). It's there to provide comfort to those who think it's required as `l` is in `%ld` for long ints. – Engineer Nov 15 '15 at 19:05