Estoy tratando de establecer el bit más significativo en un largo, largo, sin firmar, x. Para hacer eso estoy usando esta línea de código:
x |= 1<<((sizeof(x)*8)-1);
Pensé que esto debería funcionar, porque sizeof da el tamaño en bytes, así que multipliqué por 8 y resté uno para establecer el bit final. Cada vez que hago eso, el compilador tiene esta advertencia: "advertencia: recuento de desplazamiento a la izquierda> = ancho de tipo"
No entiendo por qué se produce este error.
El 1
que está cambiando es una constante de tipo int
, lo que significa que está cambiando un valor int
por tamaño de sizeof(unsigned long long) * 8) - 1
bits. Este cambio puede ser fácilmente más que el ancho de int
, que aparentemente es lo que sucedió en su caso.
Si desea obtener una máscara de bits de tipo unsigned long long
, debe comenzar con una máscara de bits inicial de tipo unsigned long long
, no de tipo int
.
1ull << (sizeof(x) * CHAR_BIT) - 1
Podría decirse que una mejor manera de construir la misma máscara sería
~(-1ull >> 1)
o
~(~0ull >> 1)
use 1ULL << en lugar de 1 <<
Usar solo "1" te hace cambiar un número entero. 1ULL será un largo sin firmar, que es lo que necesita. Un número entero será probablemente de 32 bits long long
probablemente de 64 bits de ancho. Entonces cambiando:
1 << ((sizeof(long long)*8)-1)
será (muy probablemente):
1 << 63
Dado que 1 es un número entero que es (muy probablemente) 32 bits, recibe una advertencia porque está tratando de pasar el MSB de un valor de 32 bits.
El literal 1
que está cambiando no es automáticamente un unsigned long long
(sino un int
) y, por lo tanto, no tiene tantos bits como necesita. Agregue el sufijo ULL
(es decir, 1ULL
), o conviértalo en unsigned long long
antes de cambiarlo para que sea del tipo correcto.
Además, para ser un poco más seguro para plataformas extrañas, reemplace 8
con CHAR_BIT
. Tenga en cuenta que esta no es necesariamente la mejor manera de establecer el bit más significativo; consulte, por ejemplo, esta pregunta para conocer las alternativas.
También debe considerar el uso de un tipo como uint64_t
si supone que unsigned long long
tiene un cierto ancho, o uint_fast64_t
/ uint_least64_t
si necesita al menos un cierto ancho, o uintmax_t
si necesita el tipo más grande disponible.