从 printf 切换到 cout - 复杂格式说明符模式

Switching to cout from printf - Complex format specifier patterns

作为项目要求的一部分,我必须用 C++ 重写一个日志系统(现在一切都必须是 C++ 而不是 C),我们可以通过多种方式记录数学数据和指针地址等内容。看到类似这样的日志是很常见的:

log("%3.4f %d %zp %5.8f", ...);

在 C++ 中,使用 cout 而不是 printf,设置这样的日志记录格式似乎更复杂一些,例如,从 C++ Primer Plus (Prata ):

ios_base::fmtflags initial;
initial = os.setf(ios_base::fixed); // save initial formatting state
os.precision(0);
os.setf(ios::showpoint);
os.precision(1);
os.width(12);

这看起来会为参数列表中的 所有 浮点项设置宽度和精度,并且不允许我为不同的变量设置不同的值。

cout 甚至可以仅用一行代码以简单的方式生成这样的字符串,还是我应该使用 sprintf 准备我的字符串然后将它们提供给 cout

谢谢!

质疑需求!

printfC++ 中工作正常,正确使用编译器警告可防止类型不一致。 C++ 格式化替代方案过于复杂且容易出错:很容易将流格式设置为与进入时不同的状态。

如果您确实需要使用cout,请使用snprintf()格式化日志条目并将格式化的字符串移动到cout

Can cout even generate such a string in a simple manner with just one line of code, or should I use sprintf to prepare my strings and then feed them to cout?


我同意 sprintf() 不是 C++。它只是提供了某种向后兼容性的方式......即它是专门提供的,以便您可以 post-pone 转换(从 c 到 c++)和技术债务到您的日程安排的后期。


这是我 'fixed' 日志为 C++ 时的代码示例。 (我留在 sprintf() 中以帮助记录新的 C++ 代码。)

  //retVal = ::sprintf(buff1, "%08llx  %2d:%02d:%02d,  %05llu.%03llu:  ",
  //            a_pid, hr, min, sec, (ms_of_day / 1000), (rt_ms % 1000));
  // use stringstream formatting, not sprintf
  buff1 << std::dec << std::setfill('0')  << std::setw(8) << a_pid << " "
        << std::setfill('0')  << std::setw(2) << hr   << ":"
        << std::setfill('0')  << std::setw(2) << min  << ":"
        << std::setfill('0')  << std::setw(2) << sec  << ",  "
        << std::setfill('0')  << std::setw(5) << (ms_of_day / 1000) 
        << "."
        << std::setfill('0')  << std::setw(3) << (ms_of_day % 1000) 
        << ":  ";

我只需要这样做一次。

在很多方面,我都不怀念 sprintf 的 'unsafe-type' 风格。


如果您经常做一些特别的事情,您也可以考虑创建如下内容。

std::string ssprintf0x08x(std::string label, void*  ptr)
{
   std::stringstream ss;

   ss << label << "0x"
      << std::hex << std::internal << std::setw(8) 
      << std::setfill('0')
      << reinterpret_cast<uint64_t>(ptr);

   return (ss.str());
}

我只需要实施一次。


问题答案:

Can cout even generate such a string in a simple manner with just one line of code?

是的。当然可以。

C++ 流输出有一个学习曲线,但它会引导您使用类型安全的文本输出方法。

而且,也许您已经意识到,一行代码可能会很长。