2011-11-24 2 views
5

Il codice seguente emette 0,1,32,33. Che è controintuitivo per non dire altro. Ma se sostituisco il letterale 1 con la costante annonata tipo "UNO", il ciclo funziona correttamente.Bug del compilatore di bit shift o caso d'angolo?

Questo è con gcc 4.6.2 e -std = C++ 0x.

#include<iostream> 
#include<cstdint> 
using namespace std; 
int main() 
    { 
    int64_t bitmask = 3; 
    int64_t k; 
    const int64_t ONE = 1; 
    cout<<"bitmask = "<<bitmask<<endl; 

    for(k=0; k<64; k++) 
     { 
     if(bitmask & (1<<k)) 
      { 
      cout<<"k="<<k<<endl; 
      } 
     } 

    return 0; 
    } 

EDIT Domanda: Come Ben sottolineato, 1 è visto ad essere a 32 bit di larghezza per impostazione predefinita. Perché non viene promosso a 64 bit quando il co-operando è a 64 bit.

SOLUZIONE

No. < < non richiede che ogni lato hanno lo stesso tipo. Dopo tutto, perché rendere il lato destro un int64_t quando il massimo spostamento disponibile si inserisce in un char? La promozione si verifica solo quando hai a che fare con operatori aritmetici, non con tutti gli operatori.

Copiato da commenti di Bill sotto

+1

possibile duplicato di [Come faccio a muovere un po 'più a lungo di oltre 32 bit?] (Http://stackoverflow.com/questions/2404439/how-do-i-it-shift-a-long-by- più-di-32-bit) –

risposta

7

Questo è un problema: (1<<k).

1 è un valore letterale integrato che si inserisce in un int.

Se ha meno di 64 bit sulla piattaforma, quindi (1<<k) avrà un comportamento non definito verso la fine del ciclo, quando k è grande. Nel tuo caso, il compilatore sta usando un'istruzione Intel bitshift, e il comportamento non definito viene fuori nel modo in cui Intel definisce spostamenti maggiori della dimensione dell'operando - i bit alti vengono ignorati.

probabilmente avrete bisogno (1LL<<k)


ciò che la norma dice (sezione 5.8 expr.shift):

Gli operandi devono essere di tipo di enumerazione integrale o senza ambito e le promozioni integrali vengono eseguite. Il tipo del risultato è quello dell'operando sinistro promosso. Il comportamento non è definito se l'operando destro è negativo o maggiore o uguale alla lunghezza in bit dell'operando sinistro promosso.

Ciò in contrasto con la dicitura "I normali conversioni aritmetiche vengono eseguite per operandi di operazioni aritmetiche o tipo di enumerazione." che è presente per es. addetti e sottrazione.

Questo linguaggio non è cambiato tra C++ 03 e C++ 11.

+0

Ma non dovrebbe essere promosso a int64_t dato che il co-operando è largo 64 bit. Se provate ad aggiungere un int e un float, promuoverà certamente l'int a fluttuare. – rpg

+0

@ rpg: No. '' 'non richiede che ogni lato abbia lo stesso tipo. Dopo tutto, perché rendere il lato destro un 'int64_t' quando il massimo spostamento disponibile si adatta a un' char'? La promozione si verifica solo quando hai a che fare con operatori aritmetici, non con tutti gli operatori. –

+0

@ rpg: No.Gli operandi hanno funzioni diverse (uno è un valore, l'altro è un conteggio di bit). Non avrebbe senso forzare entrambi gli operandi allo stesso tipo. In effetti, lo standard richiede che l'operando di sinistra venga promosso indipendentemente dal tipo di operando corretto. –