这个问题源于我在讨论中使用通常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
答案 0 :(得分:3)
对于ios_base
本身,没有。 showpos
和showbase
在流上调用单参数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
是上面确定的转换说明符。
在这里,我们看到showpos
和showbase
位于同一个单元格中,我相信标准隐含意味着它们位于相同的“行”中,因此 适用(可以从std::cout << std::showpos << std::showpoint << 6.0
看到以下“行”),这两个标志在这里仍然不相互排斥。
到目前为止,我们发现showpos
和showbase
在C ++中并不是唯一的,实际的格式化行为由printf
定义(尽管实现不是不需要使用printf
,例如libc ++使用sprintf
,而libstdc ++不使用 ,我们必须检查C标准。
在C中,使用+
(showpos
)与o
和x
/ X
(oct
和hex
)没有定义,因为C99§7.19.6.1/ 6和/ 8说
+
签名转换的结果始终以加号或减号开头。 ......
o
,u
,x
,X
unsigned int
参数转换为...
参数未签名,因此+
无法应用。行为未被写出,因此未定义。
将#
(showbase
)添加到d
(dec
)也是未定义的行为,因为第6条规定:
#
结果转换为“替代形式”。对于
o
转换,...对于x
(或X
)转化,...对于a
,A
,e
,{ {1}},E
,f
,F
和g
次转化,......对于G
和g
次转化,... 。对于其他转换,行为未定义。
糟糕。
因此,不仅两个标志不相互排斥,根本不定义输出。提到的方案2和3 OP可能会发生。在gcc和clang中,相互冲突的选项(G
的{{1}}和showpos
的{{1}}; oct
的{{1}})被忽略了,这给人一种错觉两个选项是相互排斥的,但标准不会保证这一点。
(免责声明:我使用n3242和n1124作为参考,最终标准可能不完全相同)
答案 1 :(得分:0)
点击谷歌搜索发现我this page,其中说明了以下内容:
请注意,负整数不会以八进制或十六进制形式打印。相反,内部位模式被解释为始终为正值。
如果这是准确的,那么showpos
什么都不做是有道理的,为什么在一个总是正数的数字前面显示+
?