uint8_t tidak bisa dicetak dengan cout


146

Saya punya masalah aneh tentang bekerja dengan integer di C ++.

Saya menulis program sederhana yang menetapkan nilai ke variabel dan kemudian mencetaknya, tetapi tidak berfungsi seperti yang diharapkan.

Program saya hanya memiliki dua baris kode:

uint8_t aa = 5;

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

Output dari program ini adalah value is

Yaitu, itu mencetak kosong untuk aa.

Ketika saya mengubah uint8_tke uint16_tkode di atas bekerja seperti pesona.

Saya menggunakan Ubuntu 12,04 (Precise Pangolin), 64-bit, dan versi kompiler saya adalah:

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

2
Kemungkinan duplikat perilaku
iintream uint8_t

Jawaban:


151

Ini tidak benar-benar mencetak kosong, tetapi kemungkinan besar karakter ASCII dengan nilai 5, yang tidak dapat dicetak (atau tidak terlihat). Ada sejumlah kode karakter ASCII yang tidak terlihat , kebanyakan dari mereka di bawah nilai 32, yang merupakan kosong sebenarnya.

Anda harus mengonversi aauntuk unsigned intmenghasilkan nilai numerik, karena ostream& operator<<(ostream&, unsigned char)mencoba menampilkan nilai karakter yang terlihat.

uint8_t aa=5;

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

24
Karena cast gaya C disukai, bukankah lebih baik melakukan static_cast?
Tim Seguine

37
Ini harus dikonversi menjadi int. Gips adalah salah satu cara untuk melakukan itu, tetapi bukan satu-satunya cara. +aajuga berfungsi.
Pete Becker

5
bukankah int (var) dan (int) var sebenarnya adalah hal yang sama?
paulm

9
Lihat pertanyaan yang ditautkan menggunakan tipe (var) sama dengan (tipe) var sama dengan C cast - coba saja dengan const dll, ia menghilangkannya!
paulm

13
Respons "Tidak. Cast gaya c tidak disarankan untuk c ++ karena sejumlah alasan." untuk "bukankah int (var) dan (int) var sebenarnya adalah hal yang sama?" yakin membuatnya seolah-olah Anda tidak menyadari int(var)dan (int)varmemiliki makna yang persis sama. int(var)berkecil hati dalam kasus-kasus persis di mana (int)var, untuk alasan yang persis sama, karena itu berarti hal yang persis sama. (Saya dapat mengerti mengapa Anda tetap menggunakannya di sini, jadi, saya tidak mengatakan Anda perlu menggunakannya static_cast. Saya hanya berpikir bahwa jejak komentar di sini agak membingungkan).

46

uint8_tkemungkinan besar akan menjadi typedefuntuk unsigned char. The ostreamkelas memiliki kelebihan khusus untuk unsigned char, yaitu mencetak karakter dengan nomor 5, yang merupakan non-printable, maka ruang kosong.


14
Saya berharap std :: uint8_t standar benar-benar diperlakukan sebagai jenis yang terpisah dan bukan hanya typedef friggin '. Tidak ada alasan waras untuk menerapkan karakter-semantik untuk tipe-tipe ini ketika digunakan bersama dengan objek stream.
antred

37

Menambahkan operator unary + sebelum variabel tipe data primitif apa pun akan memberikan nilai numerik yang dapat dicetak alih-alih karakter ASCII (untuk tipe char).

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

Itu bagus, tapi mengapa tidak c ++ memperlakukan uint8_tsebagai unsigned charyang akan menjadi nilai-nilai numerik?
R1S8K

@ R1S8K ini karena sementara uint8_thanya tipe def unsigned char, unsigned charitu sendiri ditangani oleh ostreamseperti chardan mencetak nilai ASCII-nya.
Harsh

@Harsh, terima kasih! jadi ini adalah tipe def unsigned charyang menjelaskan banyak hal. Jadi satu-satunya bilangan bulat adalah int, kan?
R1S8K

@ R1S8K Nah, tipe integer terkecil adalah short intyang membutuhkan 2 byte. Ada beberapa variasi lain dari tipe integer juga.
Harsh

@ Keras Juga saya pikir ketika memprogram dan mendeklarasikan variabel, tidak masalah jika saya mendeklarasikan variabel yang hanya akan berurusan dengan angka kecil tidak melebihi seperti 250 dengan ukuran register besar seperti longatau intkarena kompiler akan mengoptimalkan penggunaan RAM atau flash menurut apa yang mengisi daftar itu, apakah saya benar?
R1S8K

16

Itu karena operator output memperlakukan uint8_tlike a char( uint8_tbiasanya hanya alias untuk unsigned char), sehingga mencetak karakter dengan kode ASCII (yang merupakan sistem pengkodean karakter yang paling umum)5 .

Lihat misalnya referensi ini .


Mengapa? kompiler C memperlakukannya sebagai angka. Saya pikir C ++ berbeda pada saat ini.
R1S8K

@PerchEagle Jika Anda membaca referensi yang ditautkan, Anda akan melihat bahwa operator kelebihan beban untuk karakter signeddan unsignedkarakter (di luar dataran charyang dalam C ++ benar-benar tipe terpisah ketiga). Jadi jika uint8_tini adalah alias untuk unsigned char(sangat mungkin) itulah yang akan digunakan.
Beberapa programmer Bung

Bisakah Anda memeriksa jawaban saya di utas ini dan memberi tahu saya apakah jawaban saya benar atau tidak? stackoverflow.com/questions/15585267/… , jawaban saya adalah sebelum yang terakhir. Terima kasih banyak.
R1S8K

14
  • Memanfaatkan ADL (lookup nama tergantung-argumen):

    #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;
        }
    }

    keluaran:

    *
    42
  • Seorang manipulator aliran kustom juga dimungkinkan.

  • Operator plus unary juga idiom yang rapi ( cout << +i << endl).

8
Bukankah Kiss masih paradigma yang valid ??
πάντα ῥεῖ


4
@ πάνταῥεῖ ok, terus lakukan berton-ton c style gips dalam kode c ++ lalu, siapa pun bebas untuk menjadi produktif seperti itu, di lingkungan yang paling cocok untuknya.
pepper_chico

5
@ πάνταῥεῖ serius? pemeran gaya fungsional, juga, hanya casting gaya c. mengubah satu dari yang lain tidak membantu apa pun dalam meninggalkan ranah C, periksa: stackoverflow.com/a/4775807/1000282 . pete-becker mengomentari ini juga pada jawaban Anda, tetapi Anda sepertinya telah melewatkan komentar terakhirnya.
pepper_chico

3
Solusi ini sangat elegan & efektif, karena berfungsi dengan templat. Faktanya, itulah satu-satunya solusi yang saya temukan yang berfungsi untuk saya. Satu peringatan, fungsi pertama memiliki bug, karena 'os' terikat ke satu jenis, dan oleh karena itu, nilai yang ditandatangani atau tidak ditandatangani akan dikirim ke versi operator yang salah << (). Cara mengatasinya cukup sederhana:return std::is_signed<char>::value ? os << static_cast<int>(c) : os << static_cast<unsigned int>(c);
Georges

7

coutdianggap aasebagai charnilai ASCII 5yang merupakan karakter yang tidak patut intdicetak , coba ketik sebelum pencetakan.


4

The operator<<()kelebihan antara istreamdan charadalah fungsi non-anggota. Anda dapat secara eksplisit menggunakan fungsi anggota untuk memperlakukan char(atau a uint8_t) sebagai 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;
}

Keluaran:

value is 5

2

Seperti yang orang lain katakan sebelum masalah terjadi karena stream standar memperlakukan char yang ditandatangani dan char yang tidak ditandatangani sebagai karakter tunggal dan bukan sebagai angka.

Ini solusi saya dengan perubahan kode minimal:

uint8_t aa = 5;

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

Menambahkan "+0" aman dengan nomor apa pun termasuk floating point.

Untuk tipe integer akan mengubah tipe hasil menjadi intif sizeof(aa) < sizeof(int). Dan itu tidak akan berubah ketik jikasizeof(aa) >= sizeof(int) .

Solusi ini juga baik untuk mempersiapkan int8_tdicetak untuk streaming sementara beberapa solusi lainnya tidak begitu baik:

int8_t aa = -120;

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

Keluaran:

value is -120
bad value is 4294967176

Solusi PS dengan ADL yang diberikan oleh pepper_chico dan πάντα ῥεῖ benar-benar indah.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.