Representación de campo de bit con signo

5 minutos de lectura

Representacion de campo de bit con signo
Tom Slutsky

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?

Representacion de campo de bit con signo
Antti Haapala — Слава Україні

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 intdependiendo 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 intse 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 lo coloca encima de todo lo demás que está definido por la implementación con respecto a los campos de bits, su utilidad disminuye bastante

    – StoryTeller – Unslander Mónica

    1 de marzo de 2017 a las 9:13


  • Hasta donde yo sé, la representación del complemento a uno no se utiliza en gran medida.

    – Yves Daoust

    1 de noviembre de 2021 a las 10:24


  • @YvesDaoust bueno, es por eso que mi revisión anterior ya mencionó que el complemento de dos es el que usa GCC … por lo que cualquier host destinado a GCC usará el complemento de dos. Que yo sepa, no hay compiladores que admitan más arquitecturas que GCC.

    – Antti Haapala — Слава Україні

    1 de noviembre de 2021 a las 10:57


Representacion de campo de bit con signo
Un tipo programador

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.

  • ¿Puedo esperar que el campo de evety bit sea negativo cuando se llama con printf?

    – Tom Slutski

    1 de marzo de 2017 a las 9:16

  • @tomslu Depende del tipo base, su ancho y su valor. Y en el compilador (según la respuesta de Antti Haapala).

    – Un tipo programador

    1 de marzo de 2017 a las 9:18


  • “siempre use tipos sin firmar como base”: ¿por qué? Si necesita enteros con signo, use enteros con signo.

    – Yves Daoust

    1 de noviembre de 2021 a las 10:25

  • @YvesDaoust Tal vez no debería haber dicho “siempre”, pero la cantidad de casos de uso para valores firmados en un campo de bits es muy muy pequeña.

    – Un tipo programador

    1 de noviembre de 2021 a las 11:37

  • Ciertamente estoy de acuerdo con los campos de 1 bit. Para tamaños más grandes, los campos se usan a menudo como valores enumerados, para los cuales la firma es irrelevante y, con suerte, el compilador los maneja de manera consistente. Para campos de bits verdaderamente numéricos, quién sabe…

    – Yves Daoust

    1 de noviembre de 2021 a las 11:48

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad