将C风格的漂亮打印重构为C++风格的漂亮打印

3

我想将一些printf/sprintf/fprintf语句重构为ostream/sstream/fstream语句。代码中涉及了对整数和浮点数的格式化输出,包括使用空格填充和设置小数点位数。

我认为这个重构可以采用 Martin Fowler 风格的安全、逐步重构方法来完成,并注明重要注意事项。当然,第一步是将旧代码放到测试环境中,我已经完成了这一步。

我可以采取哪些缓慢而谨慎的步骤来执行此重构?


即使没有其他人愿意回答,我打算使用这篇文章作为记录我的步骤的地方,以帮助未来的他人/自己。 - Keith Pinson
1
为什么不使用一个格式化库,它提供了类似于 printf 的接口,但是是类型安全的,比如 tinyformat(https://github.com/c42f/tinyformat)? - vitaut
1
我认为这不是一个适合缓慢和仔细重构的好选择:使用霰弹枪式的重构就可以了,因为你只是用标准C++库的一部分调用替换另一部分的调用。你没有重构程序的结构,只是它的实现细节,所以只要你有一个好的测试套件,就可以放心大胆地进行尝试,一次性进行尽可能少或尽可能多的更改。 - Sergey Kalinichenko
2个回答

2
如果重构本身不是目标,则可以通过使用格式化库(如tinyformat)避免它,该库提供类似于printf的接口,但是具有类型安全性并在内部使用IOStreams。

@Kazark:我只是好奇,为什么这不是一个选项呢?是公司政策禁止了吗? - vitaut
2
Boost还提供了一个打印函数,并且它足够出名,可能是可用的。 - ssube
@Karzak:所以你们组织的政治环境更容易编写和维护自定义代码,而不是接受经过充分测试的软件包? - Ira Baxter
我接受了自己的答案,因为它更直接地回答了问题。然而,对于任何有选择权的人来说,你的答案可能是更好的选择。 - Keith Pinson
@Ira,不是因为我们的软件团队,但确实存在真实和合理的安全限制...但也有IT团队...好吧,这不是谈论它的地方,哈哈... - Keith Pinson
显示剩余2条评论

2

转换的基本机制:

  • 将每个printf风格子句%w.pf%w.pe,其中w是字段宽度,p是精度位数,转换为<< setw(w) << setprecision(p) << fixed
  • 将每个printf风格子句%wd%wi,其中w是字段宽度,转换为<< setw(w)
  • 在适当的位置将"\n"转换为endl

printf的处理过程:

  • 创建一个足够宽度的char[](我们称之为text)。
  • printf(...)转换为sprintf(text, ...),并使用cout << text来实际打印文本。
  • 完成常见指令。

fprintf的处理过程:

  • printf相同,但使用适当的fstream而不是cout
    • 如果您已经有一个打开的C-style FILE对象,而您现在不想重构它,那么会有一些棘手的问题(但可以完成)。
  • 完成常见指令。

sprintf的处理过程:

  • 如果要写入的字符串仅在当前上下文中用于输出到流,请参考上述两种重构之一。
    • 否则,首先创建一个stringstream,并将要写入的char[]内容流式传输到其中。如果您仍然打算从中提取char*,则可以使用std::stringstream::str().c_str()
  • 完成常见指令。

常见指令:

  • 逐个将每个子句转换为C++风格。
  • 必要时删除*printfchar[]声明。
  • 根据需要应用其他重构,特别是“提取方法”(Fowler,《重构》)。

1
考虑到这种转换是机械的,你应该考虑编写脚本来完成这项工作。很可能你可以非常低的错误率识别打印调用,并且如果正确执行替换,它们很可能会完全正确。 "缓慢和逐步" 可能是错误的方法。 - Ira Baxter
дљ†еПѓдї•е∞Ж "\n" дњЭзХЩдЄЇ "\n"гАВendl жЫіеГПжШѓ "\n" еРОиЈЯзЭА fflushгАВ - Nemo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接