【问题标题】:Are std::showbase and std::showpos mutually exclusive?std::showbase 和 std::showpos 是互斥的吗?
【发布时间】:2011-12-07 23:38:41
【问题描述】:

这个问题源于我正在讨论使用 C++ 中的数字类型通常使用 ostream & operator << (ostream &, some_type) 输出数值的正确方法。

我熟悉的 std::showbase 和 std::showpos 在每个基中的行为方式,它们基本上是互斥的。即:十进制不显示底数,正数加“+”;而在十六进制或八进制中,显示基数,但不显示“+”(也不是减号),因为类型的值被打印出来,就好像它被强制转换为无符号类型一样。

例如,这个简单(冗长)的程序:

#include <iostream>

int main() {
  std::cout << std::dec << std::showpos << std::showbase << int64_t(+5) << std::endl;
  std::cout << std::oct << std::showpos << std::showbase << int64_t(+5) << std::endl;
  std::cout << std::hex << std::showpos << std::showbase << int64_t(+5) << std::endl;
  std::cout << std::dec << std::showpos << std::showbase << int64_t(-5) << std::endl;
  std::cout << std::oct << std::showpos << std::showbase << int64_t(-5) << std::endl;
  std::cout << std::hex << std::showpos << std::showbase << int64_t(-5) << std::endl;
}

使用 GCC 编译时给出此输出:

+5
05
0x5
-5
01777777777777777777773
0xfffffffffffffffb

这是我一直期望的,我使用 C++ 很多年了,但这真的是标准保证的,还是这只是常见的行为?例如,符合标准的 C++ 编译器是否可以输出这些序列之一?

+5
+05
+0x5
-5
01777777777777777777773
0xfffffffffffffffb

甚至:

+5
+05
+0x5
-5
-05
-0x5

【问题讨论】:

    标签: c++ iostream ostream


    【解决方案1】:

    对于ios_base 本身,没有。 showposshowbase 在流上调用单参数 setf(§27.5.6.1[fmtflags.manip]/5 和 /13),两者互不影响。


    更深入一点,std::ostream 使用 locale::facet::put 函数打印整数 (§27.7.3.6.2[ostream.inserters.arithmetic]/1),以及它的实现 locale::facet::do_put (§22.4.2.2.2[facet.num.put.virtuals]/5) 规定:

    用于描述阶段 1 的所有表格都是有序的。也就是说,条件为真的第一行适用。当前面的行都不适用时,没有条件的行是默认行为。

    ...

    转换说明符具有以下可选附加限定符,如表 90 所示。

    表 90 - 数值转换 +------------------------+-------------------+----- -------------+ |类型 |状态 |标准输出等效 | +========================+===================+===== ==============+ | |旗帜和表演 | + | |整数类型 | | | | |旗帜和表演基地 | # | +------------------------+-------------------+----- -------------+ | |旗帜和表演 | + | |浮点类型| | | | |旗帜和展示点 | # | +------------------------+-------------------+----- -------------+

    ...

    第 1 阶段结束时的表示由将通过调用 printf(s, val) 打印的字符组成,其中 s 是上面确定的转换说明符。

    在这里,我们看到 showposshowbase 在同一个单元格中,我相信标准暗示它们在同一个“行”中,因此 两者适用(可以从std::cout &lt;&lt; std::showpos &lt;&lt; std::showpoint &lt;&lt; 6.0看到下面的“行”),并且这两个标志在这里仍然不互斥。


    到目前为止,我们看到showposshowbase在C++中并不是独占的,实际的格式化行为是由printf定义的(虽然实现不需要使用@ 987654336@,例如libc++使用sprintf,而libstdc++没有),这个我们要检查C标准。

    在 C 中,使用 + (showpos) 和 ox/X (octhex) 没有定义,因为 C99 §7.19.6.1/6 和 / 8 说

    +

    有符号 转换的结果总是以加号或减号开头。 ...

    ouxX

    unsigned int 参数被转换为 ...

    参数没有签名,所以+ 不能应用。行为未写出,因此未定义。

    # (showbase) 添加到d (dec) 也是未定义的行为,如子句/6 所述:

    #

    结果将转换为“替代形式”。对于o 转换,...​​对于x(或X)转换,...​​对于aAeEfF,@ 987654366@ 和 G 转换,...​​ 对于 gG 转换,...​​ 对于其他转换,行为未定义。

    哎呀。

    因此,不仅这两个标志不互斥,而且根本没有定义输出。可能会发生提到的场景 2 和 3 OP。在 gcc 和 clang 中,冲突的选项(showpos 代表 octhexshowbase 代表 dec)被简单地忽略,这给人一种两个选项相互排斥的错觉,但标准将不保证。

    (免责声明:我使用n3242和n1124作为参考,最终标准可能不完全相同)

    【讨论】:

    • 感谢您提供非常详细的回答。这绝对回答了我的问题!
    【解决方案2】:

    谷歌搜索找到了我this page,它在这个主题上说了以下内容:

    请注意,负整数不会以八进制或十六进制打印。相反,内部位模式被解释为始终为正值。

    如果这是准确的,那么showpos 什么都不做是有道理的,为什么在一个总是正数的数字前面显示+

    【讨论】:

    • 你说得对,它确实有意义,而且这是我见过的唯一表现方式。但是问题的目的是找出我引用的当前行为是否是事实上的约定(例如,从原始 STL 时代开始,或者因为 printf 就是这样做的,或者......等等...... ) 或者如果它实际上是标准 C++ 库的必需行为。
    猜你喜欢
    • 1970-01-01
    • 2021-11-20
    • 1970-01-01
    • 1970-01-01
    • 2021-12-02
    • 1970-01-01
    • 2021-06-04
    • 2023-04-01
    • 2012-09-22
    相关资源
    最近更新 更多