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