You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何移除Print函数中的tmp缓冲区与二次std::snprintf调用?

问题

能否移除Print函数中的tmp缓冲区以及对std::snprintf的第二次调用?能否仅通过一次std::snprintf调用实现相同功能?

编译环境:基于arm-none-eabi-g编译,启用C14、O3优化,禁用RTTI与异常,无法使用std::cout。

原代码示例:

// arm-none-eabi-g++ -std=c++14 -O3 -Wall -fno-rtti -fno-exceptions

#include <array>
#include <cstdint>
#include <cstdio>
#include <utility>

void TransmitViaUartAndDma(const char * buffer, int len) {
  // "Embedded World"
  (void)buffer;
  (void)len;
}

constexpr std::size_t buf_size = 64; // = sizeof(buffer)/sizeof(buffer[0])
std::array<char, buf_size> buffer{};

template<typename Arg, typename ...Args>
void Print(Arg&& arg, Args&&... args) {
  std::array<char, buf_size> tmp{};
  int len = std::snprintf(tmp.begin(), buffer.size(),
                                       "%s"
                                       "\n",
                                       std::forward<Arg>(arg));
  // std::printf("len = %d\n", len);
  len = std::snprintf(buffer.begin(), buffer.size(),
                                      tmp.cbegin(),
                                      std::forward<Args>(args)...);
  // std::printf("len = %d\n", len);
  TransmitViaUartAndDma(buffer.cbegin(), len);
}

int main() {
  std::uint32_t val1{222};
  std::uint32_t val2{111};
  Print("%u. %u. Hello, ", val1, val2);
  // std::printf(buffer.cbegin());
  Print("%u. %u. World!", val2, val1);
  // std::printf(buffer.cbegin());
  return 0;
}

// 预期输出:
// 222. 111. Hello, 
// 111. 222. World!
解决方案

完全可以移除tmp缓冲区和第二次std::snprintf调用,通过一次调用就能实现相同功能。

原代码的逻辑是先把传入的格式字符串和换行符拼接进tmp缓冲区,再以tmp为新的格式字符串填充参数,属于冗余操作。我们可以直接将原格式字符串与换行符合并作为std::snprintf的格式参数,一次性完成格式化:

修改后的Print函数:

template<typename Arg, typename ...Args>
void Print(Arg&& arg, Args&&... args) {
  int len = std::snprintf(buffer.begin(), buffer.size(),
                         "%s\n",
                         std::forward<Arg>(arg),
                         std::forward<Args>(args)...);
  TransmitViaUartAndDma(buffer.cbegin(), len);
}

说明

  • 原代码中第一次snprintf仅用于拼接格式字符串与换行符,第二次才是真正填充参数。我们直接用"%s\n"作为格式模板,将传入的格式字符串arg作为第一个占位符的参数,后续紧跟原有的args参数,一次调用就完成了格式拼接和参数填充。
  • 该修改移除了tmp缓冲区,减少了内存占用和一次函数调用开销,输出结果与原代码完全一致。
  • 需注意buf_size要足够容纳格式化后的内容,避免输出被截断。

内容的提问来源于stack exchange,提问作者ge45mue

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 10:23:17