uint8_tはcoutで印刷できません


146

C ++で整数を処理することについて奇妙な問題があります。

変数に値を設定して出力する簡単なプログラムを書いたが、期待どおりに動作しない。

私のプログラムには2行のコードしかありません。

uint8_t aa = 5;

cout << "value is " << aa << endl;

このプログラムの出力は value is

つまり、は空白で印刷されaaます。

上記のコードに変更uint8_tするとuint16_t、魅力のように機能します。

私は64ビットのUbuntu 12.04(Precise Pangolin)を使用していますが、コンパイラのバージョンは次のとおりです。

gcc version 4.6.3 (Ubuntu/Linaro 4.6.3-1ubuntu5)


回答:


151

実際には空白を印刷しませんが、ほとんどの場合、値5のASCII文字は印刷できません(または表示されません)。目に見えないASCII文字コードがいくつかあり、そのほとんどが値32未満です。これは実際には空白です。

目に見える文字値を出力しようとするため、数値を出力するように変換するaa必要unsigned intがありostream& operator<<(ostream&, unsigned char)ます。

uint8_t aa=5;

cout << "value is " << unsigned(aa) << endl;

24
Cスタイルのキャストは眉をひそめているので、static_castを実行するほうがいいのではないでしょうか。
Tim Seguine 2013年

37
変換する必要がありますint。キャストはそのための1つの方法ですが、唯一の方法ではありません。+aaも動作します。
ピートベッカー

5
int(var)と(int)varは実際には同じものではありませんか?
ポール、2014

9
type(var)を使用してリンクされた質問は、(type)var と同じで、Cキャストと同じです。constなどで試してみてください。削除されます。
ポール、2014

13
「いいえ。cスタイルのキャストは、さまざまな理由からc ++では推奨されていません。」「int(var)と(int)varは実際には同じものではないのですか?」確かに、あなたが気づかなかったように見え、まったく同じ意味int(var)(int)var持っています。int(var)まさにそのような場合に推奨されて(int)var、まったく同じ理由のために、あるので、それはまったく同じことを意味します。(とにかくなぜここに行くのか理解できるので、を使用する必要があるとは言っていませんstatic_cast。ここのコメントトレイルが少し不必要に混乱していると思います。)

46

uint8_t最も可能性が高くなりますtypedefためunsigned charostreamクラスはのための特別な過負荷を持っているunsigned char、それは非印字可能である5番、したがって空のスペースで文字を印刷しますすなわち。


14
標準が本当にstd :: uint8_tを別のタイプとして扱い、単なる単なるtypedefではないことを願っています。ストリームオブジェクトと組み合わせて使用​​する場合に、これらの型に文字セマンティクスを適用することにはまともな理由はありません。
2015

37

プリミティブデータ型の変数の前に単項+演算子を追加すると、(char型の場合)ASCII文字の代わりに印刷可能な数値が得られます。

uint8_t aa = 5;
cout<<"value is "<< +aa <<endl;

それはいいですが、なぜc ++ は数値になるものuint8_tとして扱わないのunsigned charですか?
R1S8K

@ R1S8Kは、uint8_tが単なる型のdefであるのに対してunsigned charunsigned charそれ自体がostreamlike によって処理されchar、そのASCII値を出力するためです。
厳しい

@厳しい感謝の男!だからそれunsigned charは多くのことを説明するタイプの定義です。つまり、唯一の整数はintですよね?
R1S8K

@ R1S8Kさて、最小の整数型はshort int2バイトを占めます。整数型には他にもいくつかのバリエーションがあります。
厳しい

@Harshまた、変数をプログラミングおよび宣言するとき、コンパイラーがRAMまたはフラッシュの使用を最適化するlongなどのint理由で、大きなレジスターサイズで250を超えない小さな数のみを処理する変数を宣言しても問題ないと思いますその記録を満たすものによると、私は正しいですか?
R1S8K

16

これは、出力演算子がuint8_ta charuint8_t通常はの単なるエイリアスunsigned char)を扱うため、ASCIIコード(最も一般的な文字エンコーディングシステム)で文字が出力されるため5です。

たとえば、このリファレンスを参照してください


どうして?Cコンパイラはそれを数値として扱います。この時点でC ++は異なると思います。
R1S8K

@PerchEagleリンクされた参照を読むと、演算子がsignedunsigned文字の両方でオーバーロードされていることがわかります(charC ++では実際には3番目の別個の型であるプレーンを超えています)。したがって、uint8_tunsigned char(非常に可能性が高い)のエイリアスである場合、それが使用されます。
一部のプログラマー、

このスレッドで私の答えを確認して、私の答えが正しいかどうか教えてください。stackoverflow.com/questions/15585267/…、私の答えは最後の答えの前です。どうもありがとうございます。
R1S8K

14
  • 使用を作るADL(引数依存名ルックアップを):

    #include <cstdint>
    #include <iostream>
    #include <typeinfo>
    
    namespace numerical_chars {
    inline std::ostream &operator<<(std::ostream &os, char c) {
        return std::is_signed<char>::value ? os << static_cast<int>(c)
                                           : os << static_cast<unsigned int>(c);
    }
    
    inline std::ostream &operator<<(std::ostream &os, signed char c) {
        return os << static_cast<int>(c);
    }
    
    inline std::ostream &operator<<(std::ostream &os, unsigned char c) {
        return os << static_cast<unsigned int>(c);
    }
    }
    
    int main() {
        using namespace std;
    
        uint8_t i = 42;
    
        {
            cout << i << endl;
        }
    
        {
            using namespace numerical_chars;
            cout << i << endl;
        }
    }

    出力:

    *
    42
  • カスタムストリームマニピュレータも可能です。

  • 単項プラス演算子もきちんとしたイディオムです(cout << +i << endl)。

8
KISSはまだ有効なパラダイムではありませんか?
ῥεῖπάντα

1
もちろん、@πάνταῥεῖですが、忘れないでください。すべてを可能な限りシンプルにする必要
pepper_chico 14年

4
@πάνταῥεῖわかりました。C++コードで大量のCスタイルのキャストを続けてください。そうすれば、誰でも、自分に最も適した環境で、自由に生産的にすることができます。
pepper_chico 14年

5
@πάνταῥεῖ真剣に?機能的なスタイルのキャストも、cスタイルのキャストです。Cのレルムを離れる際に、いずれかを変更しても何も役に立たない、チェック:stackoverflow.com/a/4775807/1000282。pete-beckerもあなたの答えについてこれにコメントしましたが、あなたは彼の最後のコメントを見逃しているようです。
pepper_chico 14年

3
このソリューションはテンプレートで機能するため、非常にエレガントで効果的です。実際、これが私が見つけた唯一の解決策です。ただし、最初の関数にはバグがあります。これは、 'os'が単一の型にバインドされているため、符号付きまたは符号なしの値が間違ったバージョンのoperator <<()に送信されるためです。修正はreturn std::is_signed<char>::value ? os << static_cast<int>(c) : os << static_cast<unsigned int>(c);
ジョルジュ


4

operator<<()間のオーバーロードistreamとはchar、非メンバ関数です。メンバー関数を明示的に使用して、char(またはuint8_t)をとして扱うことができintます。

#include <iostream>
#include <cstddef>

int main()
{
   uint8_t aa=5;

   std::cout << "value is ";
   std::cout.operator<<(aa);
   std::cout << std::endl;

   return 0;
}

出力:

value is 5

2

他の人が言ったように、問題が発生する前に、標準ストリームは、signed charとunsigned charを数値ではなく単一の文字として扱います。

これが最小限のコード変更による私のソリューションです:

uint8_t aa = 5;

cout << "value is " << aa + 0 << endl;

追加"+0"は、浮動小数点を含む任意の数で安全です。

整数型のint場合、結果の型をifに変更しますsizeof(aa) < sizeof(int)。そして、それはタイプを変更しませんsizeof(aa) >= sizeof(int)

このソリューションはint8_t、印刷してストリームする準備をするのにも適していますが、他のいくつかのソリューションはあまり良くありません。

int8_t aa = -120;

cout << "value is " << aa + 0 << endl;
cout << "bad value is " << unsigned(aa) << endl;

出力:

value is -120
bad value is 4294967176

pepper_chicoとπάνταῥεῖによって与えられたADLを使用したPSソリューションは本当に美しいです。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.