std :: showbase和std :: showpos是互斥的吗?

时间:2011-12-07 23:38:41

标签: c++ iostream ostream

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

我熟悉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

2 个答案:

答案 0 :(得分:3)

对于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所示。

                  Table 90 — Numeric conversions

+-----------------------+-------------------+------------------+
| Type(s)               | State             | stdio equivalent |
+=======================+===================+==================+
|                       | flags & showpos   | +                |
| an integral type      |                   |                  |
|                       | flags & showbase  | #                |
+-----------------------+-------------------+------------------+
|                       | flags & showpos   | +                |
| a floating-point type |                   |                  |
|                       | flags & showpoint | #                |
+-----------------------+-------------------+------------------+

     

...

     

第1阶段结束时的陈述包含将通过printf(s, val)调用打印的字符,其中s是上面确定的转换说明符。

在这里,我们看到showposshowbase位于同一个单元格中,我相信标准隐含意味着它们位于相同的“行”中,因此 适用(可以从std::cout << std::showpos << std::showpoint << 6.0看到以下“行”),这两个标志在这里仍然不相互排斥。


到目前为止,我们发现showposshowbase在C ++中并不是唯一的,实际的格式化行为由printf 定义(尽管实现不是不需要使用printf,例如libc ++使用sprintf,而libstdc ++不使用 ,我们必须检查C标准。

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

  

+

     
    

签名转换的结果始终以加号或减号开头。 ......

  
     

ouxX

     
    

unsigned int参数转换为...

  

参数未签名,因此+无法应用。行为未被写出,因此未定义。

#showbase)添加到ddec)也是未定义的行为,因为第6条规定:

  

#

     
    

结果转换为“替代形式”。对于o转换,...​​对于x(或X)转化,...对于aAe,{ {1}},EfFg次转化,......对于Gg次转化,... 。对于其他转换,行为未定义。

  

糟糕。

因此,不仅两个标志不相互排斥,根本不定义输出。提到的方案2和3 OP可能会发生。在gcc和clang中,相互冲突的选项(G的{​​{1}}和showpos的{​​{1}}; oct的{​​{1}})被忽略了,这给人一种错觉两个选项是相互排斥的,但标准不会保证这一点。

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

答案 1 :(得分:0)

点击谷歌搜索发现我this page,其中说明了以下内容:

  

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

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