为什么Boost Format和printf在相同的格式字符串上表现不同?

7

Boost Format文档中说:

其目标之一是提供printf的替代品,这意味着format可以解析为printf设计的格式化字符串,将其应用于给定的参数,并生成与printf相同的结果。

当我使用相同的格式化字符串比较boost:format和printf的输出时,我得到了不同的输出。在线示例在这里

#include <iostream>
#include <boost/format.hpp>

int main()
{
    boost::format f("BoostFormat:%d:%X:%c:%d");

    unsigned char cr =65; //'A'
    int cr2i = int(cr);

    f % cr % cr % cr % cr2i;

    std::cout << f << std::endl;
    printf("Printf:%d:%X:%c:%d",cr,cr,cr,cr2i);
}

输出结果为:
BoostFormat: A:A:A:65 printf: 65:41:A:65 不同之处在于当我想将char显示为整数类型时。
为什么会有差异?这是一个bug还是预期行为?
2个回答

6

这是期望的行为。

boost手册中,关于你使用的经典类型规范写道:

但是,在格式中,printf的经典类型规范标志具有较弱的含义。它仅在内部流和/或格式化参数上设置适当的标志,但不需要相应的参数是特定类型。

请注意,在stdlib-printf调用中,所有char参数都会自动转换为int,因为是可变参数调用。因此生成的代码与以下内容相同:

printf("Printf:%d:%X:%c:%d",cr2i,cr2i,cr2i,cr2i);

这种自动转换不是通过%运算符完成的。


1
+1 但是,哇,这太糟糕了。我想知道他们的理由是什么?看起来他们采用了C风格格式(本来就不太好),但仍然没有做到向后兼容。就像选择了两个世界中更糟糕的一样。 - user694733
感谢您的答复。很高兴知道这是期望的行为,但这不是我所期望的。在这里,实际类型会覆盖说明符。因此,对于char型,'%d'和'%c'之间没有区别,这很奇怪。 - ToBe
@user694733:Boost.Format无法根据格式字符串的内容(运行时)更改operator%的(编译时)重载。现在你可以隐藏这个问题,但这会增加显著的复杂性 - 你必须在编译时实现可能的重载方案,并在运行时选择正确的方案。这也不是空间高效的。 - MSalters
@joefel 在你的代码中,你实际上没有编写与你想输出的行为相匹配的代码。如果你想匹配printf的行为,你应该写的是 f % +cr % +cr % cr % +cr; - Peter Nimmo
1
这是使用一元+运算符执行整数提升 - 有关详细信息,请参阅https://msdn.microsoft.com/zh-cn/library/ewkkxkwb(d=hv.2,v=vs.140).aspx - Peter Nimmo

0

关于已接受的答案的补充:

这也会发生在类型为wchar_tunsigned short和其他等效类型的参数上,这可能是意外的,例如,在使用Windows API中的结构体成员(例如SYSTEMTIME)时,这些成员是历史原因上的短整数类型WORD

如果您正在使用Boost Format替换遗留代码中的printf和“类似printf”的函数,则可以考虑创建一个包装器,以覆盖%运算符,使其转换为

  • charshort转换为int
  • unsigned charunsigned short转换为unsigned int

以模拟C变量参数列表的行为。它仍然不会100%兼容,但大多数剩余的不兼容性实际上有助于修复潜在的不安全代码。

新的代码可能不应该使用Boost Format,而是使用标准std::format,它与printf不兼容。

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