Fixing MinGW-w64 Format Warnings for long double in Custom Printf Functions
The Problem: Unexpected Format Warnings on MinGW-w64
If you are developing C or C++ applications on Windows using the MinGW-w64 toolchain, you might encounter a puzzling compiler warning when writing custom printf-like wrapper functions. Even though the standard printf handles long double arguments with %Lf flawlessly, a custom wrapper annotated with __attribute__((__format__(__printf__, 1, 2))) triggers the following warning:
warning: format ‘%Lf’ expects argument of type ‘double’, but argument 2 has type ‘long double’ [-Wformat=]Why does GCC warn about your custom function while letting the standard printf pass without a peep?
The Root Cause: MSVCRT vs. GNU Printf Archetypes
The discrepancy lies in how Windows handles long double and how MinGW-w64 bridges the gap between Windows and GNU standards.
- MSVC Runtime (MSVCRT): Under Microsoft's standard C runtime, a
long doubleis represented as a 64-bit double-precision float—identical to a standarddouble. Therefore, the Microsoft-native formatting engine expects a 64-bitdoublewhen it parses%Lf. - GNU / MinGW-w64: GCC and the GNU standard treat
long doubleas an 80-bit extended-precision float. To support this on Windows, MinGW-w64 redirects standardprintfcalls to its own ANSI-compliant engine (__mingw_printf) when__USE_MINGW_ANSI_STDIOis enabled (which is the default in modern MinGW-w64 environments).
When you use __attribute__((__format__(__printf__, 1, 2))) on MinGW-w64, the compiler defaults to validating your format string against the system's native printf style (which maps to MSVC's ms_printf). Because MSVC's %Lf expects a 64-bit double, GCC generates a warning when you pass an 80-bit long double to your wrapper.
The Solution: Use the GNU Printf Archetype
To resolve this warning, you must explicitly tell GCC to validate your custom function using the GNU format archetype instead of the MSVC system archetype.
Option 1: Explicitly Use gnu_printf
Change the format attribute from __printf__ (or printf) to gnu_printf:
__attribute__((__format__(gnu_printf, 1, 2)))
void my_printf2(const char* fmt, ...)
{
va_list args;
va_start(args, fmt);
vprintf(fmt, args);
va_end(args);
}Option 2: Use the Portable MinGW Macro (Recommended)
MinGW-w64 provides a built-in macro called __MINGW_PRINTF_FORMAT. This macro automatically expands to the correct format archetype (either gnu_printf or ms_printf) depending on your compiler settings and whether ANSI stdio is enabled.
Here is how to implement it safely for cross-platform compatibility:
#include <stdio.h>
#include <stdarg.h>
#ifdef __MINGW32__
# define MY_PRINTF_FORMAT __MINGW_PRINTF_FORMAT
#else
# define MY_PRINTF_FORMAT printf
#endif
__attribute__((__format__(MY_PRINTF_FORMAT, 1, 2)))
void my_printf2(const char* fmt, ...)
{
va_list args;
va_start(args, fmt);
vprintf(fmt, args);
va_end(args);
}Summary
The warning occurs because the default __printf__ archetype on Windows targets the Microsoft format engine, which treats long double as a 64-bit double. By switching your attribute to gnu_printf or using MinGW's __MINGW_PRINTF_FORMAT macro, you align your custom wrapper with the GNU-compliant formatter, silencing the warning and ensuring robust format-string validation.