Vi el siguiente código en esta publicación de Quora :
#include <stdio.h>
struct mystruct { int enabled:1; };
int main()
{
struct mystruct s;
s.enabled = 1;
if(s.enabled == 1)
printf("Is enabled\n"); // --> we think this to be printed
else
printf("Is disabled !!\n");
}
Tanto en C como en C ++, la salida del código es inesperada ,
Está desactivado !!
Aunque la explicación relacionada con el "bit de signo" se da en esa publicación, no puedo entender cómo es posible que establezcamos algo y luego no se refleje como está.
¿Alguien puede dar una explicación más elaborada?
Nota : ambas etiquetasC Y c ++son necesarios, porque sus estándares difieren ligeramente para describir los campos de bits. Consulte las respuestas para la especificación C y la especificación C ++ .
int
creo que solo puede contener los valores0
y-1
.struct mystruct { unsigned int enabled:1; };
?Respuestas:
Los campos de bits están increíblemente mal definidos por el estándar. Dado este código
struct mystruct {int enabled:1;};
, entonces no sabemos:int:n
campo de bits debe considerarse firmado o no firmado.Con respecto a la última parte, C17 6.7.2.1/10 dice:
Nota no normativa que explica lo anterior:
En caso de que se considere el campo de bits
signed int
y se haga un poco de tamaño1
, entonces no hay espacio para los datos, solo para el bit de signo. Esta es la razón por la que su programa puede dar resultados extraños en algunos compiladores.Buena práctica:
int
para cualquier forma de manipulación de bits.fuente
¿Estás preguntando por qué se compila y te da un error?
Sí, idealmente debería darte un error. Y lo hace, si usa las advertencias de su compilador. En GCC, con
-Werror -Wall -pedantic
:El razonamiento de por qué esto se deja en manos de una implementación definida frente a un error puede tener más que ver con los usos históricos, donde requerir una conversión significaría romper el código antiguo. Los autores de la norma pueden creer que las advertencias fueron suficientes para compensar a los interesados.
Para agregar algo de prescriptivismo, me haré eco de la declaración de @ Lundin: "Nunca uses campos de bits para ningún propósito". Si tiene el tipo de buenas razones para ser de bajo nivel y específico sobre los detalles de diseño de su memoria que lo llevarían a pensar que necesitaba campos de bits en primer lugar, los otros requisitos asociados que tiene casi con certeza se encontrarán con su subespecificación.
(TL; DR: si es lo suficientemente sofisticado como para "necesitar" campos de bits legítimamente, no están lo suficientemente bien definidos para servirle).
fuente
char
, soporte para bytes que no son de 8 bits, etc. No se les permitió darles a las computadoras idiotas una desventaja de mercado.Este es el comportamiento definido por la implementación. Estoy asumiendo que las máquinas en las que está ejecutando esto usan dos enteros con signo complementario y se tratan
int
en este caso como un entero con signo para explicar por qué no ingresa si es verdadero como parte de la declaración if.declara
enable
como un campo de bits de 1 bit. Dado que está firmado, los valores válidos son-1
y0
. Establecer el campo en1
desbordamientos a los que se remonta el bit-1
(este es un comportamiento indefinido)Básicamente, cuando se trata de un campo de bits con signo, el valor máximo es el
2^(bits - 1) - 1
que es0
en este caso.fuente
-
y+
. El complemento de 2 no importa.int
como firmados en este caso. Es una pena que los campos de bits estén tan subespecificados. Básicamente, aquí está esta característica, consulte a su compilador sobre cómo usarla.Puede pensar en ello como que en el sistema de complemento a 2, el bit más a la izquierda es el bit de signo. Cualquier entero con signo con el conjunto de bits más a la izquierda es, por tanto, un valor negativo.
Si tiene un entero con signo de 1 bit, solo tiene el bit de signo. Así que la asignación
1
a ese único bit solo puede establecer el bit de signo. Entonces, al leerlo de nuevo, el valor se interpreta como negativo y también es -1.Los valores que puede contener un entero de 1 bit con signo son
-2^(n-1)= -2^(1-1)= -2^0= -1
y2^n-1= 2^1-1=0
fuente
Según el estándar n4713 de C ++, se proporciona un fragmento de código muy similar. El tipo utilizado es
BOOL
(personalizado), pero puede aplicarse a cualquier tipo.A primera vista, la parte en negrita parece abierta a la interpretación. Sin embargo, la intención correcta se vuelve clara cuando
enum BOOL
se deriva deint
.Con el código anterior, da una advertencia sin
-Wall -pedantic
:La salida es:
Si
enum BOOL : int
se simplificaenum BOOL
, la salida es como especifica el pasaje estándar anterior:Por lo tanto, se puede concluir, también como pocas otras respuestas tienen, que el
int
tipo no es lo suficientemente grande para almacenar el valor "1" en un solo campo de bits de bits.fuente
No hay nada de malo en su comprensión de los campos de bits que yo pueda ver. Lo que veo es que redefinió mystruct primero como struct mystruct {int habilitado: 1; } y luego como struct mystruct s; . Lo que debería haber codificado fue:
fuente