我必须在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>
谢谢!
答案 0 :(得分:2)
质疑要求!
printf
在C++
中正常工作,正确使用编译器警告可防止类型不一致。 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 ++流输出有一个学习曲线,但它会引导您使用类型安全的文本输出方法。
而且,也许你意识到,一行代码可能会很长。