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

时间:2015-05-04 17:26:11

标签: c++ c printf cout

我必须在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?< / p>

谢谢!

2 个答案:

答案 0 :(得分:2)

质疑要求!

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

如果确实需要使用cout,请使用snprintf()格式化日志条目并将格式化的字符串转换为cout

答案 1 :(得分:1)

  

cout甚至可以用一个简单的方式生成这样的字符串   代码行,或者我应该使用sprintf来准备我的字符串然后   喂他们到cout?

我同意sprintf()不是C ++。它只是提供了某种向后兼容性的方式......即它是专门提供的,这样你就可以将转换(c到c ++)和技术债务推迟到你日程安排的后期。

以下是我将日志“修复”为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的'不安全型'。

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

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());
}

我只需要实施一次。

回答问题:

  

cout甚至可以用一个简单的方式生成这样的字符串   代码行?

是。当然。

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

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