emio:一套专为裸机和 RTOS 环境设计的字符输入/输出库

 

emio 是啥?
emio(全称 embedded micro io)是一套专为裸机和 RTOS 环境设计的字符输入/输出库。它把 C++ 标准库里那套庞大、占内存的 I/O 抽象给压缩成了极小的二进制体积(大约只有 fmtlib 的 1/38),同时兼顾 安全(不抛异常,用 result 返回)和 高效(编译期即可完成大多数工作)。一句话:在资源紧张的 MCU 上,你想要的 printf、scanf、format,全都有,而且不需要堆。

它解决了哪些痛点?

痛点

传统做法

emio 的解决方案

二进制体积大

printf

/iostream 依赖 libc,几百KB

仅几KB,几乎不占 ROM

运行时异常

抛异常导致 MCU 难以捕获

使用 emio::result,显式检查

堆内存需求

动态分配字符串缓冲

支持 static_buffer,全栈上分配

编译期不可用

大多数库只能运行时使用

高低层 API 均可在 constexpr 环境下工作

兼容性差

只能在 POSIX 环境跑

适配裸机、FreeRTOS、Zephyr 等 RTOS

安装 & 使用

1️⃣ CMake(推荐)

FetchContent_Declare(
    emio
    GIT_TAG main
    GIT_REPOSITORY https://github.com/Viatorus/emio.git
    GIT_SHALLOW TRUE
)
FetchContent_MakeAvailable(emio)

2️⃣ 单文件:直接下载 emio.hpp(Quom 生成的单头文件)放进项目 include/ 目录。

3️⃣ Conan:在 conanfile.txt 加入 emio/0.1.0(目前在 Conan Center)。

编译器要求:支持 C++20,已在 GCC 1113、Clang 1617 上验证。

快速上手示例

// 高层 API
std::string s = emio::format("答案是 {}.", 42);
int ans{};
if (auto r = emio::scan(s, "答案是 {}.", ans); r) {
    emio::print("答案是 {}.", ans);
}

// 零堆使用
emio::static_buffer<128> buf{};
emio::format_to(buf, "十六进制 {:#x}.", 42).value();
buf.view(); // -> "十六进制 0x2a."

优缺点一览

优点

缺点

超小体积,几乎不占 ROM

仍在 beta,部分 API 可能变动

不抛异常,错误可显式处理

文档相对薄弱,社区资源少

支持 compile‑time 格式化

只针对字符 I/O,复杂协议需自行封装

高层易用、低层可控

对老旧编译器(不支持 C++20)不兼容

多平台(裸机、RTOS)

需要自行管理 static_buffer 的生命周期

小贴士

  • • 想在 ISR(中断)里打印,直接使用 emio::writer + static_buffer,省去堆分配。

  • • 若要在编译期生成日志字符串,constexpr 调用 emio::format_to 完全没有运行时开销。

  • • 记得在每次 result 检查后 if (!r) { /* 处理错误 */ },否则错误会悄悄被忽略。

总结
如果你在做资源受限的 MCU 项目,苦恼于 printf 把 ROM 吃光、异常处理又不靠谱,emio 正是为你量身定制的“轻量级 I/O”。它把高层的易用性和低层的可控性结合起来,几乎不增加代码体积,又不牺牲安全性。虽然仍在 beta 阶段,但已经足够在实际项目里替代传统 I/O 方案,值得一试。


项目地址:https://github.com/Viatorus/emio

 

发表评论