2011-11-24 12 views
5

Poniższy kod wyprowadza 0,1,32,33. Co najmniej sprzeczne z intuicją. Ale jeśli zastąpię literał 1 typem annonated constant "ONE", pętla działa dobrze.Błąd kompilatora bitowego lub narożnik?

Jest to z gcc 4.6.2 i -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 Pytanie: Jako Ben zauważył, 1 jest postrzegane jako 32 bitowe domyślnie. Dlaczego nie jest promowany do 64 bitów, gdy współoperant ma 64 bity.

ROZWIĄZANIE

nr < < nie wymaga, aby z każdej strony tego samego typu. W końcu dlaczego ustawić prawą stronę na int64_t, gdy maksymalna dostępna zmiana pasuje do znaku? Promocja występuje tylko wtedy, gdy masz do czynienia z operatorami arytmetycznymi, a nie wszystkimi operatorami.

Skopiowane z uwag Billa poniżej

+1

możliwy duplikat [Jak mogę zmienić nieco bit o ponad 32 bity?] (Http://stackoverflow.com/questions/2404439/how-do-i-bit- shift-a-long-by- więcej niż 32-bitów) –

Odpowiedz

7

jest to problem: (1<<k).

1 jest integralną literą, która pasuje do int.

Jeśli int ma mniej niż 64 bity na platformie, to (1<<k) będzie mieć niezdefiniowane zachowanie w kierunku końca pętli, gdy k będzie duże. W twoim przypadku kompilator używa instrukcji bitshift Intel, a niezdefiniowane zachowanie wychodzi tak, jak Intel definiuje przesunięcia większe niż rozmiar operandu - wysokie bity są ignorowane.

Prawdopodobnie chcesz (1LL<<k)


Co średnia mówi (sekcja 5.8 expr.shift):

Argumenty powinny być integralnym lub unscoped typu wyliczenia i integralnej promocji są wykonywane. Typ wyniku to lewy operand. Zachowanie jest niezdefiniowane, jeśli prawy operand jest ujemny lub większy lub równy długości w bitach promowanego lewego argumentu operacji.

Ten w przeciwieństwie do sformułowania „zwykłe konwersje arytmetyczne wykonywane są za argumentów arytmetyki lub typu wyliczenia.” który jest obecny np. operatory dodawania i odejmowania.

Ten język nie zmienił się między C++ 03 i C++ 11.

+0

Ale nie powinien być 1 promowany na int64_t, ponieważ jego operand ma szerokość 64 bitów. Jeśli spróbujesz dodać int i float, z pewnością będzie promował int float. – rpg

+0

@rpg: Nie. << nie wymaga, aby każda strona miała ten sam typ. W końcu dlaczego po prawej stronie należy ustawić "int64_t", gdy maksymalna dostępna zmiana pasuje do 'char'? Promocja występuje tylko wtedy, gdy masz do czynienia z operatorami arytmetycznymi, a nie wszystkimi operatorami. –

+0

@rpg: Nie.Operandy mają różne funkcje (jedna to wartość, a druga to liczba bitów). Nie ma sensu zmuszać obu operandów do tego samego typu. W rzeczywistości standard wymaga, aby lewy operand był promowany niezależnie od typu prawego argumentu. –

Powiązane problemy