Thanks to visit codestin.com
Credit goes to lib.rs

7 unstable releases (3 breaking)

Uses new Rust 2024

0.4.0 Apr 26, 2026
0.3.1 Jan 25, 2026
0.3.0 Dec 7, 2025
0.2.1 Jul 20, 2025
0.1.1 Nov 26, 2020

#23 in FFI

Codestin Search App Codestin Search App Codestin Search App Codestin Search App Codestin Search App Codestin Search App Codestin Search App Codestin Search App Codestin Search App Codestin Search App Codestin Search App Codestin Search App Codestin Search App Codestin Search App Codestin Search App Codestin Search App Codestin Search App

6,453 downloads per month
Used in 14 crates (7 directly)

MIT/Apache

48KB
807 lines

printf-compat

Crates.io Docs.rs

printf reimplemented in Rust

This is a complete reimplementation of printf in Rust, using the unstable (i.e. requires a Nightly compiler) c_variadic feature.

  • Many C libraries provide a way to provide a custom log callback. With this crate, you can provide a pure Rust option, and do whatever you want with it. Log it to the console, store it in a string, or do anything else.
  • If you're writing a Rust-first program for a microcontroller and need to interface with a C library, you might not have a libc and have to reimplement it yourself. If it uses printf, use this crate to easily add your own output. core::fmt too big? No problem! Write your own formatting code, or use a minimal formatting library like ufmt or defmt. Don't need every single option given by printf format strings? No problem! Just don't implement it.
  • Likewise, if you're using wasm32-unknown-unknown instead of emscripten (as wasm-bindgen is only compatible with the former), you have no libc. If you want to interface with a C library, you'll have to do it all yourself. With this crate, that turns into 5 lines instead of hundreds for printf.

Benefits

⚒ Modular

printf-compat lets you pick how you want to output a message. Use pre-written adapters for fmt::Write (like a String) or io::Write (like io::stdout()), or implement your own.

🔬 Small

This crate is no_std compatible (with default-features = false). The main machinery doesn't require the use of core::fmt, and it can't panic.

🔒 Safe (as can be)

Of course, printf is completely unsafe, as it requires the use of va_list. However, outside of that, all of the actual string parsing is written in completely safe Rust. No buffer overflow attacks!

The n format specifier, which writes to a user-provided pointer, is considered a serious security vulnerability if a user-provided string is ever passed to printf. It is supported by this crate; however, it doesn't do anything by default, and you'll have to explicitly do the writing yourself.

🧹 Tested

A wide test suite is used to ensure that many different possibilities are identical to glibc's printf. Differences are documented.

Getting Started

Start by adding the unstable feature:

#![feature(c_variadic)]

Now, add your function signature:

use core::ffi::{c_char, c_int};

#[unsafe(no_mangle)]
unsafe extern "C" fn c_library_print(str: *const c_char, args: ...) -> c_int {
    todo!()
}

Think about what you're doing:

  • If you're implementing printf because you don't have one, you'll want to call it printf and add #[unsafe(no_mangle)].
  • Likewise, if you're creating a custom log function for a C library and it expects to call a globally-defined function, keep #[unsafe(no_mangle)] and rename the function to what it expects.
  • On the other hand, if your C library expects you to call a function to register a callback (example 1, example 2), remove #[unsafe(no_mangle)].

Now, add your logic:

use printf_compat::{format, output};
let mut s = String::new();
let bytes_written = format(str, args, output::fmt_write(&mut s));
println!("{}", s);
bytes_written

Of course, replace output::fmt_write with whatever you like—some are provided for you in output. If you'd like to write your own, follow their function signature: you need to provide a function to format() that takes an Argument and returns the number of bytes written (although you don't need to if your C library doesn't use it) or -1 if there was an error.

License: MIT OR Apache-2.0

Dependencies

~555KB
~11K SLoC