///
/// printf.c provides "printf, dummy_printf_do_f_impl, printf_do_f_fp"
///
void dummy_printf_do_f_impl()
{
printf("Uh oh - you used %%f but didn't use the float keyword anywhere!!"); abort();
// alternatively, you could dynamically load the floating point library here, for example to handle the case where the main program's "printf" has been passed a float from a plugin.
}
extern FARPROC printf_do_f_fp = &dummy_printf_do_f_impl;
... printf(...)
{
case "f": printf_do_f_fp();
}
///
/// flt.lib provides __fltused, requires _printf_fp_impl
///
int __fltused;
void* force_load_printf_fp = &actual_printf_do_f_impl;
///
/// printf_fp.c in printf_fp.lib (provides _printf_fp_impl)
///
printf_do_f.c requires __fltused
FARPROC printf_do_f = NULL;
void actual_printf_do_f_impl()
{
printf("Here's your float: ", ...etc...);
}
extern
class InitMagicNumber
{
InitMagicNumber()
{
printf_do_f = &actual_printf_do_f_impl;
}
}
_printf_fp_impl;
// Now follow through the compilation of main.c (main() { printf("This should return an error: %f"); }
main.c requires printf, provided by printf.lib. printf.lib doesn't require any printf_fp stuff, so that's not loaded. Now when printf is called, it does normal printf behaviour until it hits %f, when it then calls printf_do_f_fp, which is a symbol in printf.lib defined to point to dummy_printf_do_f_impl, which triggers an error.
// Now follow through the compilation of main_fp.c (main() { printf("This should work: %f", 0.0f); }
main_fp.c uses floating point, so automatically requires __fltinit. It calls printf, so we load printf.lib. printf.lib doesn't use printf_fp, so that doesn't automatically trigger a load there, but we're now left with one unresolved symbol: __fltinit. __fltinit is defined in flt.lib, which requires the symbol _printf_fp_impl, defined in printf_fp.lib. This requires the printf_do_f_fp symbol which resolves to the definition in printf.lib. printf_fp.lib also has a "magic" variable and the linker will add its constructor to the list of CRT initialization functions.
Now when main_fp.c runs, the CRT will call all of the constructors in turn, including the InitMagicNumber magic class, which sets printf_do_f (from printf.lib) to point to actual_printf_do_f_impl. The CRT eventually calls main who calls printf, who eventually calls the deref of printf_do_f_fp, which now takes it to actual_printf_do_f_impl.
Result: printf floating point code is only brought along for the ride if you actually use floating point (or are dumb enough to include an extern int __fltused) somewhere in your code. Otherwise, a dummy implementation of printf will handle the case where %f is used on a non-floating-point program, which can either load the expensive fp library, or can explode, or can return "0.0" or whatever.