uint8_t non può essere stampato con cout


146

Ho uno strano problema nel lavorare con numeri interi in C ++.

Ho scritto un semplice programma che imposta un valore su una variabile e quindi lo stampa, ma non funziona come previsto.

Il mio programma ha solo due righe di codice:

uint8_t aa = 5;

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

L'output di questo programma è value is

Cioè, stampa in bianco per aa.

Quando cambio uint8_tal uint16_tcodice sopra funziona come un fascino.

Uso Ubuntu 12.04 (Precise Pangolin), 64-bit, e la mia versione del compilatore è:

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

2
Possibile duplicato del comportamento di iostream
uint8_t

Risposte:


151

In realtà non stampa uno spazio vuoto, ma molto probabilmente il carattere ASCII con valore 5, che non è stampabile (o invisibile). Esistono numerosi codici di caratteri ASCII invisibili , molti dei quali inferiori al valore 32, che in realtà è lo spazio vuoto.

Devi convertire aain unsigned intper generare il valore numerico, dal momento che ostream& operator<<(ostream&, unsigned char)tenta di produrre il valore del carattere visibile.

uint8_t aa=5;

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

24
Poiché i cast in stile C sono disapprovati, non sarebbe meglio fare un static_cast?
Tim Seguine,

37
Dovrebbe essere convertito in int. Un cast è un modo per farlo, ma non l'unico modo. +aafunziona anche.
Pete Becker,

5
int (var) e (int) var non sono in realtà la stessa cosa?
paulm,

9
Vedere la domanda collegata usando type (var) è uguale a (type) var è uguale al cast C - provalo con const etc, lo rimuove!
paulm,

13
La risposta "No. I cast in stile c sono scoraggiati per c ++ per una serie di ragioni." a "int (var) e (int) var non sono in realtà la stessa cosa?" sicuramente ti sembra di non aver realizzato int(var)e di (int)varavere esattamente lo stesso significato. int(var)è scoraggiato esattamente in quei casi in cui si (int)vartrova, esattamente per le stesse ragioni, perché significa esattamente la stessa cosa. (Riesco a capire perché dovresti provarlo qui, comunque, quindi non sto dicendo che devi usarlo static_cast. Penso solo che la traccia dei commenti qui sia un po 'inutilmente confusa.)

46

uint8_tsarà molto probabilmente un typedefper unsigned char. La ostreamclasse ha un sovraccarico speciale per unsigned char, cioè stampa il personaggio con il numero 5, che non è stampabile, quindi lo spazio vuoto.


14
Vorrei che lo standard trattasse davvero std :: uint8_t come un tipo separato e non solo un errore di battitura. Non vi è alcun motivo ragionevole di applicare la semantica dei caratteri a questi tipi se utilizzato in combinazione con oggetti stream.
antred

37

L'aggiunta di un operatore + unario prima della variabile di qualsiasi tipo di dati primitivo fornirà un valore numerico stampabile invece del carattere ASCII (nel caso del tipo di carattere).

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

È carino, ma perché c ++ non tratta uint8_tcome unsigned charvalori numerici?
R1S8K,

@ R1S8K questo è perché mentre uint8_tè solo un tipo def di unsigned char, esso unsigned charstesso è gestito da ostreamlike chare stampa il suo valore ASCII.
Duro

@Harsh Grazie amico! quindi è una definizione di tipo unsigned charche spiega molto. Quindi l'unico numero intero è int, giusto?
R1S8K,

@ R1S8K Bene, il tipo intero più piccolo sarebbe short intche occupa 2 byte. Vi sono anche alcune altre varianti del tipo intero.
Duro

@Harsh Inoltre penso che quando programmo e dichiari le variabili, non importa se dichiaro una variabile che si occuperebbe solo di numeri piccoli non superiori a 250 con una grande dimensione del registro come longo intperché il compilatore ottimizzerebbe l'uso di RAM o flash secondo cosa riempie quel registro, ho ragione?
R1S8K,

16

È perché l'operatore di output tratta uint8_tcome un char(di uint8_tsolito è solo un alias per unsigned char), quindi stampa il carattere con il codice ASCII (che è il sistema di codifica dei caratteri più comune) 5.

Vedi ad esempio questo riferimento .


Perché? il compilatore C lo considera come un numero. Penso che C ++ sia diverso a questo punto.
R1S8K,

@PerchEagle Se leggi il riferimento collegato vedrai che l'operatore è sovraccarico di entrambi signede unsignedcaratteri (oltre al semplice charche in C ++ è davvero un terzo tipo separato). Quindi, se uint8_tè un alias per unsigned char(molto probabilmente) è quello che verrà utilizzato.
Qualche programmatore, amico,

Potresti controllare la mia risposta su questa discussione e dirmi se la mia risposta è giusta o no? stackoverflow.com/questions/15585267/… , la mia risposta è prima dell'ultima. Grazie mille.
R1S8K,

14
  • Facendo uso di ADL (ricerca dei nomi dipendente dall'argomento):

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

    produzione:

    *
    42
  • Sarebbe anche possibile un manipolatore di flussi personalizzato.

  • Anche l'operatore plus unario è un idioma pulito ( cout << +i << endl).

8
KISS non è ancora un paradigma valido ??
πάντα ῥεῖ

1
@ πάνταῥεῖ ovviamente, ma non dimenticare: tutto dovrebbe essere reso il più semplice possibile, ma non più semplice
pepper_chico

4
@ πάνταῥεῖ ok, continua a fare tonnellate di cast in stile c nel codice c ++, quindi chiunque è libero di essere produttivo così com'è, nell'ambiente che più si adatta.
pepper_chico,

5
@ πάνταῥεῖ sul serio? cast di stile funzionale, inoltre, è solo casting in stile c. cambiare l'uno dall'altro non aiuta in nulla a lasciare il regno di C, controllare: stackoverflow.com/a/4775807/1000282 . pete-becker ha commentato anche questo sulla tua risposta, ma sembra che tu abbia perso il suo ultimo commento.
pepper_chico,

3
Questa soluzione è molto elegante ed efficace, perché funziona con i modelli. In effetti, questa è l'unica soluzione che ho notato che funziona per me. Un avvertimento, tuttavia, la prima funzione ha un bug, perché 'os' è associato a un singolo tipo e, pertanto, il valore con segno o senza segno verrà inviato alla versione errata dell'operatore << (). La correzione è abbastanza semplice:return std::is_signed<char>::value ? os << static_cast<int>(c) : os << static_cast<unsigned int>(c);
Georges,


4

Il operator<<()sovraccarico tra istreame charè una funzione non membro. È possibile utilizzare esplicitamente la funzione membro per trattare un char(o un uint8_t) come un 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;
}

Produzione:

value is 5

2

Come altri hanno già detto, il problema si verifica perché lo stream standard considera il carattere con segno e il carattere senza segno come caratteri singoli e non come numeri.

Ecco la mia soluzione con modifiche minime al codice:

uint8_t aa = 5;

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

Aggiunta "+0" è sicura con qualsiasi numero compreso il virgola mobile.

Per i tipi interi cambierà il tipo di risultato in intif sizeof(aa) < sizeof(int). E non cambierà tipo sesizeof(aa) >= sizeof(int) .

Questa soluzione è anche buona per prepararsi int8_tad essere stampata per lo streaming mentre alcune altre soluzioni non sono così buone:

int8_t aa = -120;

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

Produzione:

value is -120
bad value is 4294967176

La soluzione PS con ADL data da pepper_chico e πάντα ῥεῖ è davvero bella.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.