5

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
4

2 回答 2

3

ios_base其本身而言,没有。showpos并在流上showbase调用单参数setf(§27.5.6.1[fmtflags.manip]/5 和 /13),两者互不影响。


更深入地讲,astd::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)where sis 上面确定的转换说明符打印的字符组成。

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


到目前为止,我们看到showpos并且showbase在 C++ 中并不排斥,并且实际的格式化行为是由定义的printf (尽管实现不需要使用printf,例如 libc++ 使用sprintf,而 libstdc++ 不需要),我们必须检查 C 标准.

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

+

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

o, u, x,X

unsigned int参数转换为...

参数未签名,因此+不能适用。该行为未写出,因此未定义。

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

#

结果被转换为“替代形式”。对于o转换,...​​对于x(或X)转换,...​​对于a, A, e, E, f, F, g, 和G转换,...​​对于gG转换,...​​对于其他转换,行为未定义。

哎呀。

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

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

于 2011-12-08T01:54:43.047 回答
0

谷歌搜索找到了我这个页面,上面写着关于这个主题的以下内容:

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

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

于 2011-12-08T00:27:36.430 回答