2011-11-24 5 views
5

El siguiente código muestra 0,1,32,33. Lo cual es contra intuitivo por decir lo menos. Pero si reemplazo el literal 1 con el tipo constante anual "ONE", el ciclo funciona bien.¿Error del compilador del cambio de bit o una caja de esquina?

Esto es con gcc 4.6.2 y -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; 
    } 

EDITAR Pregunta: Como Ben señaló, 1 se ve que es de 32 bits de ancho por defecto. ¿Por qué no se promueve a 64 bits cuando su co-operando es de 64 bits?

SOLUCIÓN

Nº < < no requiere que cada lado tiene el mismo tipo. Después de todo, ¿por qué convertir el lado derecho en int64_t cuando el desplazamiento máximo disponible cabe en un char? La promoción solo ocurre cuando se trata de operadores aritméticos, no de todos los operadores.

Copiado de los comentarios de Bill a continuación

+1

posible duplicado de [¿Cómo cambio un bit de largo en más de 32 bits?] (Http://stackoverflow.com/questions/2404439/how-do-i-bit-shift-a-long-by- más de 32 bits) –

Respuesta

7

Este es un problema: (1<<k).

1 es un literal integral que cabe en un int.

Si int tiene menos de 64 bits en su plataforma, a continuación, (1<<k) tendrá un comportamiento indefinido hacia el final del bucle, cuando k es grande. En su caso, el compilador usa una instrucción Intel bitshift, y el comportamiento indefinido aparece de la misma manera que Intel define los cambios más grandes que el tamaño del operando: los bits altos se ignoran.

es probable que desee (1LL<<k)


Qué dice la norma (sección 5.8 expr.shift):

Los operandos deben ser del tipo de enumeración integral o sin ámbito y promociones integrales se llevan a cabo. El tipo de resultado es el del operando izquierdo promovido. El comportamiento no está definido si el operando derecho es negativo, o mayor o igual que la longitud en bits del operando izquierdo promovido.

Esto en contraste con la expresión "Las conversiones aritméticas habituales se llevan a cabo para operandos de la aritmética o tipo de enumeración." que está presente por ej. operadores de suma y resta.

Este lenguaje no cambió entre C++ 03 y C++ 11.

+0

Pero no debería promoverse 1 a int64_t ya que su co-operando tiene 64 bits de ancho. Si intentas agregar un int y un float, ciertamente promovería el int para flotar. – rpg

+0

@rpg: No. '<<' no requiere que cada lado tenga el mismo tipo. Después de todo, ¿por qué hacer del lado derecho un 'int64_t' cuando el desplazamiento máximo disponible cabe en un' char'? La promoción solo ocurre cuando se trata de operadores aritméticos, no de todos los operadores. –

+0

@rpg: No.Los operandos tienen diferentes funciones (una es un valor, la otra es una cuenta de bits). No tendría sentido obligar a ambos operandos al mismo tipo. Y, de hecho, el estándar requiere que el operando izquierdo sea promovido independientemente del tipo de operando correcto. –

Cuestiones relacionadas