5

ostream & operator << (ostream &, some_type)この質問は、C++ で通常の数値型を使用して数値を出力する正しい方法についての議論から生じました。

各ベースでの std::showbase と std::showpos の動作に精通している方法では、基本的に相互に排他的です。つまり、10 進数では基数は表示されず、正の数には「+」が追加されます。一方、16 進数または 8 進数では基数が表示されますが、型の値が符号なし型にキャストされたかのように出力されるため、「+」は表示されません (マイナスも表示されません)。

たとえば、次の単純な (冗長な) プログラムは次のとおりです。

#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++ コンパイラは、代わりにこれらのシーケンスの 1 つを出力できますか?

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

あるいは:

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

2 に答える 2

3

それios_base自体は、いいえ。ストリームで単一の引数(§27.5.6.1[fmtflags.manip]/5 および /13)showposを呼び出しますが、この 2 つは互いに影響しません。showbasesetf


さらに詳しく説明すると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 の説明で使用されるすべての表は順序付けされています。つまり、条件が true である最初の行が適用されます。条件のない行は、前の行がどれも適用されない場合のデフォルトの動作です。

...

変換指定子には、表 90 に示されているように、次のオプションの追加修飾子が先頭に追加されています。

                  表 90 — 数値変換

+-------------------------------------+-------------------+----- --------------+
| | タイプ | 状態 | stdio 相当 |
+=======================+==================+===== =============+
| | | | 旗とショーポス | + |
| | 整数型 | | | | |
| | | | フラグとショーベース | # |
+-------------------------------------+-------------------+----- --------------+
| | | | 旗とショーポス | + |
| | 浮動小数点型 | | | | |
| | | | フラグとショーポイント | # |
+-------------------------------------+-------------------+----- --------------+

...

ステージ 1 の最後の表現は、上で決定された変換指定子であるprintf(s, val)whereの呼び出しによって出力される char で構成されます。s

ここでは、showposshowbaseが同じセルにあることがわかります。これは、標準が暗黙的にそれらが同じ「行」にあることを意味しているため、両方が適用されると信じています (std::cout << std::showpos << std::showpoint << 6.0次の「行」から見ることができます)。ここでは、2 つのフラグはまだ相互に排他的ではありません。


showposこれまでのところ、 と は C++ で排他的ではないことがわかりshowbase、実際の書式設定の動作はprintf (ただし、実装では を使用する必要はありませんprintf。たとえば、libc++ では が使用されますがsprintf、libstdc++ では使用されません)によって定義されます。これは、C 標準を確認する必要があります。 .

Cでは、C99 §7.19.6.1/6および/8が言うため、+( showpos)ox/ X(octおよび)を使用することは定義されていませんhex

+

符号付き変換の結果は、常にプラス記号またはマイナス記号で始まります。...

ouxX

unsigned int引数は次のように変換されます...

引数は署名されていないため、+は適用できません。動作は書き出されていないため、未定義です。

#節 /6 が言うように、 ( showbase) をd( ) に追加するdecことも未定義の動作です。

#

結果は「代替形式」に変換されます。o変換の場合 ... (xまたはX) 変換の場合 ... aAeEf、および変換の場合 ...Fおよび変換の場合 ...その他の変換の場合、動作は未定義です。gGgG

おっとっと。

したがって、2 つのフラグが相互に排他的ではないだけでなく、出力がまったく定義されていません。上記のシナリオ 2 および 3 の OP が発生する可能性があります。gcc と clang では、競合するオプション ( showposforocthex; showbasefor dec) は単純に無視されるため、2 つのオプションが相互に排他的であるという錯覚が生じますが、標準はそれを保証しません。

(免責事項: n3242 と n1124 を参照として使用しています。最終的な基準はまったく同じではない可能性があります)

于 2011-12-08T01:54:43.047 に答える
0

少しグーグルで調べたところ、この件に関して次のようなページが見つかりました。

負の整数は、8 進数または 16 進数として出力されないことに注意してください。むしろ、内部ビット パターンは常に正の値として解釈されます。

これが正確であれば、何もしないのは理にかなってshowposます。なぜ+常に正の数の前に a を表示するのでしょうか?

于 2011-12-08T00:27:36.430 に答える