【问题标题】:iostream equivalent to snprintf(NULL, 0, format_string, args...)iostream 等效于 snprintf(NULL, 0, format_string, args...)
【发布时间】:2023-03-29 10:54:01
【问题描述】:

我想找出流格式化操作在不从堆中分配内存的情况下会产生的字符数。在 C 中,可以使用

int nchars = snprintf(NULL, 0, format_string, args...);

如何在C++的ostream框架内完成?

std::ostringstream 的实现可以从堆中分配内存:

template <class T>
int find_nchar(const T& value) {
  std::ostringstream os; // may allocate memory from the heap
  os << value;
  return os.str().size(); // may allocate memory from the heap
}

我想我需要制作一个自定义的 ostream 类来实现这一点。自定义 ostream 应该尊重可以为普通 std::ostream 设置的所有格式标志。

我正在寻找只使用 C++ 标准库的解决方案,例如,不使用 boost::iostreams。

【问题讨论】:

  • 也许能用stackoverflow.com/q/8243743/560648构建一些东西
  • 我觉得你的结局想法是对的。
  • 关于你的工程,你可以看看 Boost.Interprocess'bufferstream,它是固定大小的stringstream 等价物。
  • @LightnessRacesinOrbit 谢谢你的评论,我现在澄清我正在寻找一个没有外部依赖的解决方案。
  • 您只想流式传输一个值吗?

标签: c++ iostream


【解决方案1】:

与自定义 std::ostream 相比,实现自定义 std::streambuf 可能更容易(也许更灵活),然后可以与任何 std::ostream 一起使用。

#include <streambuf>

template <class CharT, class Traits = std::char_traits<CharT>>
struct counting_streambuf: std::basic_streambuf<CharT, Traits> {
  using base_t = std::basic_streambuf<CharT, Traits>;
  using typename base_t::char_type;
  using typename base_t::int_type;

  std::streamsize count = 0;

  std::streamsize xsputn(const char_type* /* unused */, std::streamsize n)
    override
    {
      count += n;
      return n;
    }

  int_type overflow(int_type ch)
    override
    {
      ++count;
      return ch;
    }

};

然后用作...

#include <iostream>

int
main (int argc, char **argv)
{
  using char_type = decltype(std::cout)::char_type;

  counting_streambuf<char_type> csb;

  /*
   * Associate the counting_streambuf with std::cout whilst
   * retaining a pointer to the original std::streambuf.
   */
  auto *oldbuf = std::cout.rdbuf(&csb);
  std::cout << "Some text goes here...\n";

  /*
   * Restore the original std::streambuf.
   */
  std::cout.rdbuf(oldbuf);
  std::cout << "output length is " << csb.count << " characters\n";
}

运行上述结果...

output length is 23 characters

编辑:原始解决方案没有超载overflow。这适用于 Linux,但不适用于 Windows。感谢 Boost 的 Peter Dimov,他找到了解决方案。

【讨论】:

  • 谢谢,这看起来很不错!我是否还必须覆盖 sputn(...) 和 sputc(...)?
  • 我认为您不必对sputn 做任何事情——它是非虚拟的,默认实现应该调用最派生的xsputn 实现。同样sputc 不是虚拟的,因此您必须依赖基本实现。不过据我所知,这一切都应该没问题。
  • 相关问题(但不重复)stackoverflow.com/questions/41377045/…
  • 此代码在带有 msvc 的 Windows 上失败。看起来 xsputn 从未被调用过。
  • 在输出序列的末尾添加&lt;&lt; std::flush 有帮助吗?我相当肯定xsputn 会在某个时候被调用。如果刷新没有帮助,我可以再看看我拥有的其他代码。
猜你喜欢
  • 2016-05-04
  • 1970-01-01
  • 2020-10-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-04-15
相关资源
最近更新 更多