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 double is represented as a 64-bit double-precision float—identical to a standard double. Therefore, the Microsoft-native formatting engine expects a 64-bit double when it parses %Lf.
  • GNU / MinGW-w64: GCC and the GNU standard treat long double as an 80-bit extended-precision float. To support this on Windows, MinGW-w64 redirects standard printf calls to its own ANSI-compliant engine (__mingw_printf) when __USE_MINGW_ANSI_STDIO is 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.