找到你要的答案

Q:Switching to cout from printf - Complex format specifier patterns

Q:切换到cout从printf格式说明符类型复杂

I have to rewrite a logging system in C++ as part of project requirements (everything has to be C++ instead of C now), and there are a number of ways in which we log things like mathematical data and pointer addresses. It is fairly common to see a log like:

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

In C++, using cout instead of printf, it seems a bit more of an involved process to setup such a logging format, eg, taking the following snippet from 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);

This looks like it will set the width and precision for all floating point items in the argument list, and won't allow me to have different values for different variables.

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?

Thanks!

我要重写测井系统在C++作为项目要求的一部分(都是C++而不是现在),也有一些方法,我们记录的东西,像数学数据和指针地址。这是相当常见的看到像日志:

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

在C++中,使用cout代替printf,这似乎有点更多的参与过程中设置这样的日志格式,例如,把下面的代码片段从C++ Primer Plus(煎饼):

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

这似乎会设置参数列表中所有浮点项目的宽度和精度,并且不允许我对不同的变量有不同的值。

法院甚至产生这样的字符串可以用简单的方式只需要一行代码,或者我应该使用sprintf准备我的字符串,然后喂给法院?

谢谢!

answer1: 回答1:

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?


I agree that sprintf() is not C++. It merely provides some manner of backward compatibility ... i.e. it has been provided specifically so that you can post-pone the conversion (of c to c++) and that technical debt to later in your schedule.


Here is a code sample from when I 'fixed' a log to be C++. (I left in the sprintf() to help document the new C++ code.)

  //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) 
        << ":  ";

I only had to do this once.

In a lot of ways, I do not miss the 'unsafe-type' style of sprintf.


If there is something special you do often, you might also consider creating something like the following.

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

I only had to implement this one time.


Answer to question:

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

Yes. Of course.

C++ stream output has a learning curve, but it leads you to a type-safe approach for text output.

And, perhaps you are realizing, one line of code can be quite long.

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++。它只提供了一些向后兼容的方式…即它提供了专门让你可以把转换(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) 
        << ":  ";

我只能这样做一次。

在很多方面,我不会错过的“安全型”风格的函数。


如果你经常做一些特别的事情,你也可以考虑创建如下的东西。

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++流输出有一个学习曲线,但它会导致你的文本输出类型安全的方法。

而且,也许你意识到,一行代码可以相当长。

answer2: 回答2:

Question the requirements!

printf works fine in C++, proper use of compiler warnings prevent type inconsistencies. The C++ formatting alternative is too complicated and error prone: it is so easy to leave the stream formatting in a different state than upon entry.

If you really need to use cout, use snprintf() to format the log entry and shift the formatted string to cout.

质疑要求!

C++中的printf精品,正确使用编译器警告防止类型不一致。C++格式的选择过于复杂和容易出错的:它是那么容易离开流格式在不同的状态比在入境。

如果你真的需要使用cout,使用snprintf()格式化日志和格式化字符串移位至cout。

c++  c  printf  cout