2014-06-07 8 views
5

ho provato a fare funzionare il seguente codice:Bitshifting in C++ che produce la risposta sbagliata

char c = (2 << 7) >> 7 

che dovrebbe restituire 0, perché 2 ha questa rappresentazione binaria come char:

0 0 0 0 0 0 1 0 

Dopo 7 turni di sinistra , otteniamo

0 0 0 0 0 0 0 0 

Quindi, dopo sette turni a destra, otteniamo

0 0 0 0 0 0 0 0 

Comunque, sto ottenendo il risultato come 2, non 0.

Il compilatore dice che 2 << 7 è di 256, ma è un char e quindi non dovrebbe essere 256.

capisco che il 2 << 7 sarà calcolato come int s e la risposta sarà messo in c così 256 >> 7 è 2.

ho cercato di lanciare 2 a char (es: (char)2>>7), ma non funziona neanche.

Sto cercando di estrarre ogni bit dal char, così ho scritto questo codice:

char c = 0x02; 
for(int i=0;i<7;i++) 
{ 
    char current = (c<<i)>>7; 
} 

Come posso ottenere ogni bit? Cosa c'è che non va in questo modo?

+6

'2 << 7' * non * è un' char'. –

+2

Si prega di non sostituire il testo della domanda con "risolto grazie" se si capisce cosa c'è che non va. Invece, aggiungi una risposta spiegando cosa non ha funzionato. – templatetypedef

+0

Ho dimenticato ma questo è un vero capriccio. – haccks

risposta

7

Il risultato di un'operazione di spostamento aritmetico con un operando pari a int in C++ è sempre un int. Pertanto, quando si scrive

current = (c << i) >> 7; 

C++ interpreterà (c << i) e (c << i) >> 7 come int s, gettando di nuovo ad un char solo quando l'assegnazione è fatto. Poiché i valori temporanei sono int s, non si verifica un overflow e il risultato deve essere restituito al risultato intero assegnato a char.

Spero che questo aiuti!

+0

l'ho appena fatto, ty – MyNick

+0

Come mai int to char conversion (demotion) è non avvisato in C++? Perché non richiede il casting esplicito? C++ è di tipo rigoroso, giusto? – texasbruce

+0

@texasbruce C++ consente conversioni implicite tra i suoi tipi interi primitivi senza cast esplicito. Se si attivano le impostazioni di avviso sul compilatore, è possibile che venga visualizzato un avviso, sebbene non sia necessario. Mentre C++ ha una digitazione statica, poiché consente esplicitamente queste conversioni, non c'è errore di tipo. – templatetypedef

4

Per ottenere ogni bit, si potrebbe scrivere:

(c >> i) & 0x01 

Vantaggio: funziona per qualsiasi tipo integer.

+1

Sì, questo è il modo di fare. Su alcune piattaforme questa è solo un'istruzione di prova a bit singolo. Spostando sopra il massimo del tipo si può richiamare un comportamento indefinito –

4

Secondo 5,8 [expr.shift] paragrafo 1:

... Gli operandi sono di tipo censimento integrale o senza ambito e promozioni integrali vengono eseguite. Il tipo del risultato è quello dell'operando sinistro promosso. ...

questo per un argomento a sinistra di tipo char insieme alle norme in materia di promozione intero (4,5 [conv.prom]) dice che il risultato è int. Naturalmente, uno int può contenere il risultato di 2 << 7.Si può facilmente verificare questo comportamento anche:

#include <iostream> 

void print(char c) { std::cout << "char=" << int(c) << "\n"; } 
void print(int i) { std::cout << "int=" << i << "\n"; } 

int main() 
{ 
    print(2 << 7); 
} 

L'approccio più semplice per ottenere i bit di un valore deve utilizzare un std::bitset<N> con N essendo le cifre del tipo senza segno corrispondente, ad esempio:

char c('a'); 
std::bitset<std::numeric_limits<unsigned char>::digits> bits(c); 

Se si desidera ottenere i bit da soli ci si mascherare i bit utilizzando il suo omologo unsigned di tipo intero, ad esempio:

template <typename T> 
void get_bits(T val) 
{ 
    typedef typename std::make_unsigned<T>::type U; 
    U value(val); 
    for (std::size_t s(std::numeric_limits<U>::digits); s-- != 0;) { 
     std::cout << bool(value & (1u << s)); 
    } 
    std::cout << '\n'; 
}