uint8_t cout ile basılamaz


146

C ++ 'da tamsayılarla çalışma konusunda garip bir sorunum var.

Bir değişkene bir değer ayarlayan ve daha sonra yazdıran basit bir program yazdım, ancak beklendiği gibi çalışmıyor.

Programımda yalnızca iki satır kod var:

uint8_t aa = 5;

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

Bu programın çıktısı value is

Yani boş kalıyor aa.

Ben değiştirdiğinizde uint8_tiçin uint16_tyukarıdaki kod bir cazibe gibi çalışır.

Ubuntu 12.04 (Precise Pangolin), 64 bit kullanıyorum ve derleyici sürümüm:

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


Yanıtlar:


151

Gerçekten boş bir sayfa yazdırmaz, ancak büyük olasılıkla yazdırılamaz (veya görünmez) 5 değerine sahip ASCII karakteri. Bir dizi var görünmeyen ASCII karakter kodları aslında boştur değerinin 32 aşağıya çoğu.

Görünür karakter değerini çıkarmaya çalıştığından , sayısal değeri çıktılamak için dönüştürmeniz aagerekir .unsigned intostream& operator<<(ostream&, unsigned char)

uint8_t aa=5;

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

24
C stili yayınlar kaşlarını çattığından, static_cast yapmak daha iyi olmaz mıydı?
Tim Seguine

37
Bu edilmelidir dönüştürülmüş için int. Oyuncular bunu yapmanın bir yoludur, ama tek yol değildir. +aaayrıca çalışır.
Pete Becker

5
int (var) ve (int) var aslında aynı şey değil mi?
paulm

9
Tür (var) kullanarak bağlantılı soruya bakın (tür) ile aynıdır C dökümü ile aynıdır - const vb. İle deneyin, kaldırır!
paulm

13
"Hayır. C stili dökümler, çeşitli nedenlerden dolayı c ++ için önerilmez." int (var) ve (int) var aslında aynı şey değil mi? emin, farkına varmamış int(var)ve (int)vartam olarak aynı anlama sahipmişsiniz gibi görünmesini sağlar . int(var)Tam olarak bu durumlarda önerilmez (int)var, aynı nedenden dolayı çünkü tam olarak aynı şeyi ifade eder. (Yine de neden burada gittiğinizi anlayabiliyorum, bu yüzden kullanmanız gerektiğini söylemiyorum static_cast. Buradaki yorum

46

uint8_tbüyük olasılıkla bir typedefolacak unsigned char. ostreamSınıf için özel bir aşırı vardır unsigned char, bu olmayan basılabilir numarası 5, dolayısıyla boş alanı olan bir karakter basar yani.


14
Standart gerçekten tedavi std :: uint8_t sadece bir aylaklık 'typedef değil, ayrı bir tür olarak diliyorum. Akış nesneleriyle birlikte kullanıldığında bu türlere karakter-anlambilim uygulamak için akılcı bir neden yoktur.
antred

37

Herhangi bir ilkel veri türünün değişkeninden önce bir tekli + operatörünün eklenmesi, ASCII karakteri yerine (char tipi olması durumunda) yazdırılabilir sayısal değer verecektir.

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

Bu güzel, ama neden ++ tedavi c değil uint8_tolarak unsigned charsayısal değerler olurdu?
R1S8K

@ R1S8K, uint8_tbunun sadece bir tür def olmasına rağmen unsigned char, unsigned charkendisi ostreamgibi charASCII değerini yazdırır ve yazdırır.
Sert

@Harsh Teşekkürler adamım! bu yüzden unsigned charçok açıklayan bir tür def . Yani tek tam sayı int, değil mi?
R1S8K

@ R1S8K short int2 bayt alan en küçük tamsayı türü olacaktır . Tamsayı tipinde başka birkaç varyasyon da vardır.
Sert

@Harsh Ayrıca, değişkenleri programlarken ve bildirirken, yalnızca 250 gibi büyük olmayan bir kayıt boyutuna sahip küçük sayıları ele alacak longveya intderleyici RAM veya flash kullanımını optimize edeceği için bir değişken beyan edersem önemli değil. kayıt olan dolgulara göre, haklı mıyım?
R1S8K

16

Bunun nedeni, çıkış operatörünün uint8_ta char( uint8_tgenellikle yalnızca bir diğer addır unsigned char) gibi davranmasıdır , bu nedenle karakteri ASCII koduyla (en yaygın karakter kodlama sistemi olan) yazdırır 5.

Bkz. Örneğin bu referans .


Neden? C derleyicisi sayı olarak kabul eder. Bu noktada C ++ farklı olduğunu düşünüyorum.
R1S8K

@PerchEagle Eğer operatör ikisi için aşırı olduğunu göreceksiniz bağlantılı başvuru okursanız signedve unsigned(düz ötesinde karakterler charC ++ gerçekten üçüncü ayrı bir türüdür). Yani eğer (büyük olasılıkla) uint8_tiçin bir takma ad unsigned charkullanılacak.
Bazı programcı ahbap

Bu konudaki cevabımı kontrol edip cevabımın doğru olup olmadığını söyleyebilir misiniz? stackoverflow.com/questions/15585267/… , cevabım sonuncusundan önce. Çok teşekkür ederim.
R1S8K

14
  • Yararlanarak ADL (değişken bağımlı ad arama):

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

    çıktı:

    *
    42
  • Özel bir akış manipülatörü de mümkündür.

  • Tekli artı operatörü de temiz bir deyimdir ( cout << +i << endl).

8
Is not KISS hala geçerli bir paradigma ??
ῥεῖντα ῥεῖ


4
@ ῥεῖνταῥεῖ tamam, c ++ kodunda tonlarca c stili atma yapmaya devam edin, o zaman herkes en uygun olduğu ortamda olduğu gibi üretken olmakta özgürdür.
pepper_chico

5
@ πάνταῥεῖ cidden mi? fonksiyonel tarzı döküm, ayrıca, sadece c tarzı döküm olduğunu. birini diğerinden değiştirmek C alemini terk etmede hiçbir işe yaramaz, kontrol edin: stackoverflow.com/a/4775807/1000282 . pete-becker bunu cevabınıza da yorumladı, ancak son yorumunu kaçırmış görünüyorsunuz.
pepper_chico

3
Bu çözüm çok zarif ve etkilidir, çünkü şablonlarla çalışır. Aslında, benim için işe yarayan tek çözüm bu. Yine de bir uyarı, ilk işlevin bir hatası vardır, çünkü 'os' tek bir türe bağlıdır ve bu nedenle, imzalı veya imzasız değer operatörün yanlış sürümüne gönderilir << (). Düzeltme yeterince basit:return std::is_signed<char>::value ? os << static_cast<int>(c) : os << static_cast<unsigned int>(c);
Georges

7

coutdavranıyor aaolarak charASCII değerinin 5yazdırılamayan karakter, için typecasting deneyin intyazdırmadan önce.


4

operator<<()Arasında aşırı yük istreamve charbir üye olmayan fonksiyonudur. A char(veya a uint8_t) işlevini a olarak ele almak için üye işlevini açıkça kullanabilirsiniz 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;
}

Çıktı:

value is 5

2

Diğerlerinin de söylediği gibi, standart akış imzalı karakter ve imzasız karakterlere sayı olarak değil, tek karakter olarak davranır.

İşte benim minimum kod değişiklikleri ile benim çözüm:

uint8_t aa = 5;

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

"+0"Kayan nokta dahil herhangi bir sayı ile ekleme yapmak güvenlidir.

Tamsayı türleri için sonuç türünü intif olarak değiştirir sizeof(aa) < sizeof(int). Ve eğer türü değişmez sizeof(aa) >= sizeof(int).

Bu çözüm, int8_tdiğer bazı çözümler o kadar iyi olmasa da akışa yazdırılmaya hazırlanmak için de iyidir:

int8_t aa = -120;

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

Çıktı:

value is -120
bad value is 4294967176

Pepper_chico ve πάντα ῥεῖ tarafından verilen ADL ile PS Çözümü gerçekten çok güzel.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.