Hice un campo de bits con un tamaño de campo de 1 bit y usé int
en lugar de unsigned
. Más tarde, cuando traté de verificar el valor del campo, encontré que el valor era -1. Usé este código para verificar la representación binaria y el valor de mi campo de bits:
#include <stdio.h>
#include <stdlib.h>
union {
struct {
int bit:1;
} field;
int rep;
} n;
int main() {
int c, k;
n.field.bit=1;
for (c = 31; c >= 0; c--)
{
k = n.rep >> c;
if (k & 1)
printf("1");
else
printf("0");
}
printf("\n %d \n", n.field.bit);
return 0;
}
la salida fue: 000000000000000000000000000000001
-1
En ese caso, ¿por qué el valor de mi campo de bits es -1 y siempre es un número negativo cuando uso int firmado en lugar de sin firmar?
Nunca debes usar simple int
como el tipo de campo de bits si espera algo sobre el valor además de que puede aguantar n
bits: de acuerdo con el estándar C11, en realidad está definido por la implementación si int
en un campo de bits está firmado o sin firmar 6.7.2p5:
5 Cada uno de los conjuntos múltiples separados por comas designa el mismo tipo, excepto que para los campos de bits, es definido por la implementación si el especificador int
designa el mismo tipo que signed int
o del mismo tipo que unsigned int
.
en tu caso el int
designa el mismo tipo que signed int
; esto es el valor predeterminado en GCC:
Si un campo de bits int “simple” se trata como un campo de bits int con signo o como un campo de bits int sin signo (C90 6.5.2, C90 6.5.2.1, C99 y C11 6.7.2, C99 y C11 6.7.2.1 ).
Por defecto se trata como signed int
pero esto puede ser cambiado por el -funsigned-bitfields
opción.
Por lo tanto, cualquier programa cuerdo siempre especifica cualquiera signed int
o unsigned int
dependiendo de cuál sea apropiado para el caso de uso actual.
Luego, se define la implementación si los números con signo están en el complemento de uno o en el complemento de dos, o tal vez el signo y la magnitud, si están en el complemento de uno o s-and-m, entonces el único valor que se puede almacenar en 1 bit es el bit de signo, por lo tanto 0; por lo tanto, el campo de bits con signo de un bit probablemente solo tenga sentido con el complemento a 2.
Su sistema parece usar el complemento de 2: esto es, por ejemplo lo que GCC siempre usa:
Si los tipos enteros con signo se representan mediante signo y magnitud, complemento a dos o complemento a uno, y si el valor extraordinario es una representación trampa o un valor ordinario (C99 y C11 6.2.6.2).
GCC solo admite tipos enteros en complemento a dos y todos los patrones de bits son valores ordinarios.
y por lo tanto los valores de bit 1
y 0
se interpretan en términos de números en complemento a dos con signo: el primero tiene establecido un bit de signo, por lo que es negativo (-1
) y el último no tiene un bit de signo establecido, por lo que no es negativo (0
).
Por lo tanto, para un campo de bits con signo de 2 bits, los posibles patrones de bits y sus valores enteros en una máquina de complemento a 2 son
00
– posee int
valor 0
01
– posee int
valor 1
10
– posee int
valor -2
11
– posee int
valor -1
En un campo de n bits, el número mínimo con signo es – 2^(n – 1) y el máximo es 2^(n-1) – 1.
Ahora, cuando la aritmética se realiza en un operando entero con signo cuyo rango es menor que int
se convierte en un int
primero, y por lo tanto el valor -1
es señal extendida a ancho completo int
; lo mismo sucede para promociones de argumento predeterminado; el valor se extiende con signo a (ancho completo) int
cuando se pasa a printf
.
Por lo tanto, si espera un valor razonable de un campo de bits de un bit, use cualquiera unsigned bit: 1;
o, alternativamente, si esto debe entenderse como una bandera booleana, _Bool bit: 1;
Cuando llamas a una función de argumento variadic (como printf
) algunos argumentos son promovido. Por ejemplo, los campos de bits sufren una promoción entera donde es ascendido a ordinario int
valor. Esa promoción trae consigo extensión de signo (porque su tipo base para el campo de bits está firmado). Esta extensión de señal lo hará -1
.
Cuando use campos de bits, casi siempre use tipos sin firmar como base.