spec %#o %#x %#o %#X %.0d %.2d %-2d arg 0 0 1 1 0 1 1 C89 printf 0 0 01 0X1 01 1 Go fmt.Printf 0 0x0 01 0X1 01 1 Py 2 print '...' % 0 0x0 01 0X1 01 1 Py 3 print('...' %) 0o0 0x0 0o1 0X1 0 01 1 Java 8 Sys.out.printf 00 0x0 01 0X1 (n/a) (n/a) 1 C++23 std::print 0 0x0 01 0X1 (n/a) (n/a) 1 Py 3 print(f'...') 0o0 0x0 0o1 0X1 (n/a) (n/a) 1 Rust print! 0o0 0x0 0o1 0x1 0 1 1 for Rust, {:.0}, {:.2} and {:-2} were used instead of {:.0d}, {:.2d} and {:-2d} because the latter don't compile. for %.0d and %.2d, precisions on integral types, C++23, Python 3 and Java 8 error out while Rust ignores the precision so my takeaways are: - the '-' flag doesn't always denote left alignment and may turn out to be a silent no-op - in C and C++, %#x and %#o may not output a prefix when the argument is zero, so avoid them for uniform output; for example, in C and C++, %#.2x and %#04x are likely bugged - with integral types, default to zero-padding to a field width instead of using a precision, just because the latter is ill-supported; for example, default to %02x instead of %.2x - ideally avoid the '#', '+' and ' ' flags when zero-padding an integral type to a field width, so the digit count matches the field width; for example, prefer 0x%02x and %#.2x to %#04x - if you so wish, use precisions and field widths on integral types semantically; specifically, consider the output if the '#' flag were toggled or the argument were negative documentation: https://cplusplus.com/reference/cstdio/fprintf/ https://pkg.go.dev/fmt https://docs.python.org/2/library/stdtypes.html#string-formatting https://docs.python.org/3/library/stdtypes.html#old-string-formatting https://docs.oracle.com/javase/8/docs/api/java/util/Formatter.html https://en.cppreference.com/w/cpp/utility/format/spec https://docs.python.org/3/library/string.html#formatspec https://doc.rust-lang.org/std/fmt/index.html https://zig.guide/standard-library/advanced-formatting/ https://github.com/ziglang/zig/issues/19488#issuecomment-2203005231 vim:et:ts=8:sw=8: