This means that when compiling for an unhosted environment (say bare-metal), you must provide inttypes.h yourself if you want to provide a standards-compliant printf that can handle fixed-width types.
No, it does not mean that at all.
Perhaps you have the wrong idea about the fixed-width types. Those that are provided by a given implementation (which need not be any of them at all) are usually standard integer types of that implementation. The type names declared in stdint.h
are then aliases for appropriate standard types, not designations of extended integer types.
Thus, the macros in question define string literals that ordinarily contain a standard conversion specifier, possibly with a length modifier, such as "d"
, "hu"
, or "lx"
. If you want to provide a printf
compatible with the one a hosted environment would provide, then you need to support all the standard conversion specifiers and all the length modifiers relevant to each one, entirely without regard whether those macros are defined or what their replacement text may be.
I guess it's possible that you would run into an implementation (even a hosted one) that provides fixed-width types that it in fact does not use among its standard integer types. To support such types with your printf
, you would probably need to extend it to provide new conversion specifiers, but in that case, that's part of your printf
implementation, so you know how to define the corresponding macros.
Any way around, the macros are relevant only to printf
callers, not implementers, except inasmuch as you might find it convenient to write definitions of those macros in conjunction with implementing printf
.
I cannot figure out how to correctly determine at compile-time what each macro should be without manually inspecting the implementation's stdint.h [...] Is there a standard way to do this?
No. That's why the macros are provided by the implementation in the first place. However, callers don't necessarily need to know. They can instead convert their fixed-width types to guaranteed-wide-enough standard types of their implementation, and use the correct standard conversion specifier for that type. That's cheap and pretty easy with printf
. If you also mean to provide a scanf
, however, then the corresponding adapter code is a little less convenient.