¿Es seguro usar -1 para establecer todos los bits en true?


He visto que este patrón se usa mucho en C & C++.

unsigned int flags = -1;  // all bits are true

¿Es esta una buena manera portátil de lograr esto? ¿O es mejor usar 0xffffffff o ~0?

Author: Antonio, 2009-05-01

19 answers

Te recomiendo que lo hagas exactamente como lo has mostrado, ya que es el más directo. Inicializar a -1 que funcionará siempre, independientemente de la representación del signo real, mientras que ~ a veces tendrá un comportamiento sorprendente porque tendrá que tener el tipo de operando correcto. Solo entonces obtendrá el valor más alto de un tipo unsigned.

Para un ejemplo de una posible sorpresa, considere esta:

unsigned long a = ~0u;

No necesariamente almacenará un patrón con todos los bits 1 en a. Pero primero creará un patrón con todos los bits 1 en un unsigned int, y luego lo asignará a a. Lo que sucede cuando unsigned long tiene más bits es que no todos son 1.

Y considere esta, que fallará en una representación de complemento de no dos:

unsigned int a = ~0; // Should have done ~0u !

La razón es que ~0 tiene que invertir todos los bits. Invertir eso producirá -1 en una máquina de complemento de dos (que es el valor que necesitamos!), pero no cederá -1 en otra representación. En una máquina de complemento, produce cero. Por lo tanto, en la máquina de complemento de uno, lo anterior inicializará a a cero.

Lo que debes entender es que todo se trata de valores, no de bits. La variable se inicializa con un valor . Si en el inicializador modifica los bits de la variable utilizada para la inicialización, el valor se generará de acuerdo con esos bits. El valor que necesita, para inicializar a al más alto valor posible, es -1 o UINT_MAX. El segundo dependerá del tipo de a - necesitará usar ULONG_MAX para un unsigned long. Sin embargo, el primero no dependerá de su tipo, y es una buena manera de obtener el valor más alto.

Estamos no hablando de si -1 tiene todos los bits uno (no siempre lo tiene). Y estamos no hablando de si ~0 tiene todos los bits uno (tiene, por supuesto).

Pero de lo que estamos hablando es de lo que el resultado de la variable inicializada flags es. Y para ello, solo -1 trabajará con cada tipo y máquina.

 150
Author: Johannes Schaub - litb,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-03-12 23:28:40
  • unsigned int flags = -1; es portátil.
  • unsigned int flags = ~0; no es portátil porque se basa en una representación de dos complementos.
  • unsigned int flags = 0xffffffff; no es portátil porque asume ints de 32 bits.

Si desea establecer todos los bits de una manera garantizada por el estándar C, use el primero.

 43
Author: Dingo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-11-21 09:03:25

Francamente creo que todos los fff's son más legibles. En cuanto al comentario de que es un antipatrón, si realmente te importa que todos los bits estén configurados/despejados, argumentaría que probablemente estés en una situación en la que te importe el tamaño de la variable de todos modos, lo que requeriría algo como boost::uint16_t, etc.

 24
Author: Doug T.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-04-30 21:42:34

Una forma de evitar los problemas mencionados es simplemente hacer:

unsigned int flags = 0;
flags = ~flags;

Portátil y al grano.

 17
Author: hammar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-05-01 13:26:28

No estoy seguro de que usar un int sin signo para las banderas sea una buena idea en primer lugar en C++. ¿Qué acerca de bitset y similares?

std::numeric_limit<unsigned int>::max() es mejor porque 0xffffffff asume que unsigned int es un entero de 32 bits.

 13
Author: Edouard A.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-12-10 05:26:20
unsigned int flags = -1;  // all bits are true

"¿Es esta una buena[,] manera portátil de lograr esto?"

Portátil? .

Bueno? Discutible, como lo demuestra toda la confusión mostrada en este hilo. Ser lo suficientemente claro para que sus compañeros programadores puedan entender el código sin confusión debería ser una de las dimensiones que medimos para un buen código.

Además, este método es propenso a advertencias del compilador. Para eludir la advertencia sin paralizar su compilador, necesitarías un elenco explícito. Por ejemplo,

unsigned int flags = static_cast<unsigned int>(-1);

El cast explícito requiere que prestes atención al tipo de destino. Si estás prestando atención al tipo de objetivo, entonces naturalmente evitarás las trampas de los otros enfoques.

Mi consejo sería prestar atención al tipo de destino y asegurarse de que no hay conversiones implícitas. Por ejemplo:

unsigned int flags1 = UINT_MAX;
unsigned int flags2 = ~static_cast<unsigned int>(0);
unsigned long flags3 = ULONG_MAX;
unsigned long flags4 = ~static_cast<unsigned long>(0);

Todos los cuales son correctos y más obvios para sus compañeros programadores.

Y con C++11 : Podemos usar auto para hacer cualquiera de estos aún más simple:

auto flags1 = UINT_MAX;
auto flags2 = ~static_cast<unsigned int>(0);
auto flags3 = ULONG_MAX;
auto flags4 = ~static_cast<unsigned long>(0);

Considero correcto y obvio mejor que simplemente correcto.

 10
Author: Adrian McCarthy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-05-02 12:35:52

Convertir -1 en cualquier tipo sin signo es garantizado por el estándar para dar como resultado todos-unos. El uso de ~0U es generalmente malo ya que 0 tiene el tipo unsigned int y no llenará todos los bits de un tipo sin signo más grande, a menos que escriba explícitamente algo como ~0ULL. En sistemas sanos, ~0 debería ser idéntico a -1, pero dado que el estándar permite representaciones de complemento y signo/magnitud, estrictamente hablando no es portátil.

Por supuesto, siempre está bien escribir out 0xffffffff si sabe que necesita exactamente 32 bits, pero -1 tiene la ventaja de que funcionará en cualquier contexto incluso cuando no sepa el tamaño del tipo, como macros que funcionan en varios tipos, o si el tamaño del tipo varía según la implementación. Si conoce el tipo, otra forma segura de obtener todas las macros son las macros de límite UINT_MAX, ULONG_MAX, ULLONG_MAX, etc.

Personalmente siempre uso -1. Siempre funciona y no tienes que pensar en ello.

 9
Author: R..,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-08-01 21:02:49

Sí. Como se mencionó en otras respuestas, -1 es el más portable; sin embargo, no es muy semántico y activa las advertencias del compilador.

Para resolver estos problemas, pruebe este sencillo ayudante:

static const struct All1s
{
    template<typename UnsignedType>
    inline operator UnsignedType(void) const
    {
        return static_cast<UnsignedType>(-1);
    }
} ALL_BITS_TRUE;

Uso:

unsigned a = ALL_BITS_TRUE;
uint8_t  b = ALL_BITS_TRUE;
uint16_t c = ALL_BITS_TRUE;
uint32_t d = ALL_BITS_TRUE;
uint64_t e = ALL_BITS_TRUE;
 5
Author: Diamond Python,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-07-16 05:32:57

Mientras tengas #include <limits.h> como uno de tus includes, solo debes usar

unsigned int flags = UINT_MAX;

Si quieres un largo de bits, se podría utilizar

unsigned long flags = ULONG_MAX;

Se garantiza que estos valores tengan todos los bits de valor del resultado establecidos en 1, independientemente de cómo se implementen los enteros con signo.

 5
Author: Michael Norrish,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-01-04 00:23:31

No haría lo de -1. Es bastante no intuitivo (al menos para mí). Asignar datos firmados a una variable sin firmar parece ser una violación del orden natural de las cosas.

En tu situación, siempre uso 0xFFFF. (Por supuesto, utilice el número correcto de Fs para el tamaño variable.)

[POR cierto, rara vez veo el truco -1 hecho en código del mundo real.]

Además, si realmente te importan los bits individuales en un vairable, sería buena idea comenzar a usar el ancho fijo uint8_t, uint16_t, uint32_t tipos.

 3
Author: myron-semack,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-12-10 05:24:21

En los procesadores IA-32 de Intel está bien escribir 0xFFFFFFFF en un registro de 64 bits y obtener los resultados esperados. Esto se debe a que IA32e (la extensión de 64 bits a IA32) solo admite inmediatez de 32 bits. En instrucciones de 64 bits los inmediatos de 32 bits son signo extendido a 64 bits.

Lo siguiente es ilegal:

mov rax, 0ffffffffffffffffh

Lo siguiente pone 64 1s en RAX:

mov rax, 0ffffffffh

Solo para completar, lo siguiente pone 32 1s en la parte inferior de RAX (también conocido como EAX):

mov eax, 0ffffffffh

Y de hecho, he tenido programas fallan cuando quería escribir 0xffffffff a una variable de 64 bits y obtuve un 0xffffffffffffffff. En C esto sería:

uint64_t x;
x = UINT64_C(0xffffffff)
printf("x is %"PRIx64"\n", x);

El resultado es:

x is 0xffffffffffffffff

Pensé en publicar esto como un comentario a todas las respuestas que decían que 0xFFFFFFFF asume 32 bits, pero mucha gente respondió que pensé que lo añadiría como una respuesta separada.

 2
Author: Nathan Fellman,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-05-02 10:53:37

Ver la respuesta de litb para una explicación muy clara de los problemas.

Mi desacuerdo es que, muy estrictamente hablando, no hay garantías para ninguno de los casos. No conozco ninguna arquitectura que no represente un valor sin signo de 'uno menos de dos a la potencia del número de bits' como todos los bits establecidos, pero esto es lo que el Estándar realmente dice (3.9.1 / 7 más nota 44):

Las representaciones de tipos integrales definirán valores mediante el uso de un binario puro sistema de numeración. [Nota 44:] Una representación posicional para enteros que utiliza los dígitos binarios 0 y 1, en la que los valores representados por bits sucesivos son aditivos, comienzan con 1, y se multiplican por la potencia integral sucesiva de 2, excepto quizás para el bit con la posición más alta.

Eso deja la posibilidad de que uno de los bits sea cualquier cosa.

 2
Author: James Hopkin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-05-12 13:41:33

Prácticamente: Sí

Teóricamente: No.

-1 = 0xFFFFFFFF (o cualquier tamaño que tenga un int en su plataforma) solo es verdadero con la aritmética de complemento de dos. En la práctica, funcionará, pero hay máquinas heredadas (mainframes de IBM, etc.).) donde tienes un bit de signo real en lugar de una representación de complemento de dos. La solución ~0 propuesta debería funcionar en todas partes.

 1
Author: Drew Hall,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-04-30 21:41:52

Aunque el 0xFFFF (o 0xFFFFFFFF, etc.) puede ser más fácil de leer, puede romper la portabilidad en el código que de otro modo sería portátil. Considere, por ejemplo, una rutina de biblioteca para contar cuántos elementos en una estructura de datos tienen determinados bits establecidos (los bits exactos son especificados por el llamante). La rutina puede ser totalmente agnóstica en cuanto a lo que representan los bits, pero todavía necesita tener una constante "todos los bits establecidos". En tal caso, -1 será mucho mejor que una constante hexadecimal, ya que funcionará con cualquier tamaño.

La otra posibilidad, si se usa un valor typedef para la máscara de bits, sería usar ~(bitMaskType)0; si bitmask sucede que solo es un tipo de 16 bits, esa expresión solo tendrá 16 bits configurados (incluso si 'int' de otro modo sería 32 bits) pero como 16 bits serán todo lo que se requiere, las cosas deberían estar bien siempre que uno realmente use el tipo apropiado en el encasillamiento.

Por cierto, las expresiones de la forma longvar &= ~[hex_constant] tienen una mala atrapada si el maleficio constante es demasiado grande para caber en un int, pero cabrá en un unsigned int. Si un int es 16 bits, entonces longvar &= ~0x4000; o longvar &= ~0x10000; borrará un bit de longvar, pero longvar &= ~0x8000; borrará el bit 15 y todos los bits por encima de eso. Los valores que encajan en int tendrán el operador complemento aplicado a un tipo int, pero el resultado se extenderá a long, estableciendo los bits superiores. Los valores que son demasiado grandes para unsigned int tendrán el operador complemento aplicado al tipo long. Valores que se encuentran entre esos tamaños, sin embargo, aplicará el operador complemento a type unsigned int, que luego se convertirá a type long sin extensión de signo.

 1
Author: supercat,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-12-10 16:09:34

Como otros han mencionado, -1 es la forma correcta de crear un entero que se convertirá a un tipo sin signo con todos los bits establecidos en 1. Sin embargo, lo más importante en C++ es usar los tipos correctos. Por lo tanto, la respuesta correcta a su problema (que incluye la respuesta a la pregunta que hizo) es esta:

std::bitset<32> const flags(-1);

Esto siempre contendrá la cantidad exacta de bits que necesita. Construye un std::bitset con todos los bits establecidos en 1 por las mismas razones mencionadas en otras respuestas.

 1
Author: David Stone,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-12-12 02:26:58

Es ciertamente seguro, ya que -1 siempre tendrá todos los bits disponibles establecidos, pero me gusta ~0 mejor. -1 simplemente no tiene mucho sentido para un unsigned int. 0xFF... no es bueno porque depende del ancho del tipo.

 0
Author: Zifre,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-04-30 21:40:28

Yo digo:

int x;
memset(&x, 0xFF, sizeof(int));

Esto siempre le dará el resultado deseado.

 0
Author: Alex,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-10-11 11:28:57

Aprovechando el hecho de que asignar todos los bits a uno para un tipo sin signo es equivalente a tomar el valor máximo posible para el tipo dado,
y extendiendo el alcance de la pregunta a todos los tipos enteros sin signo :

Asignar -1 funciona para cualquier tipo entero sin signo (int sin signo, uint8_t, uint16_t, etc.) para C y C++.

Como alternativa, para C++, puede:

  1. Incluir <limits> y utilizar std::numeric_limits< your_type >::max()
  2. Escriba una función templada personalizada (Esto también permitiría una comprobación de cordura, es decir, si el tipo de destino es realmente un tipo sin signo)

El propósito podría ser agregar más claridad, ya que asignar -1 siempre necesitaría algún comentario explicativo.

 0
Author: Antonio,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 10:31:10

Sí, la representación que se muestra es muy correcta, ya que si lo hacemos al revés, u requerirá un operador para revertir todos los bits, pero en este caso la lógica es bastante sencilla si consideramos el tamaño de los enteros en la máquina

Por ejemplo, en la mayoría de las máquinas, un entero es de 2 bytes = 16 bits el valor máximo que puede contener es 2^16-1=65535 2^16=65536

0%65536=0 -1% 65536 = 65535 que corresponde a 1111.............1 y todos los bits se establecen en 1 (si consideramos clases de residuos mod 65536) por lo tanto, es muy sencillo.

Supongo

No si u considerar esta noción es perfectamente dine para ints sin firmar y realmente funciona

Basta con comprobar el siguiente fragmento del programa

Int principal() {

unsigned int a=2;

cout<<(unsigned int)pow(double(a),double(sizeof(a)*8));

unsigned int b=-1;

cout<<"\n"<<b;

getchar();

return 0;

}

Respuesta para b = 4294967295 whcih es -1% 2^32 en enteros de 4 bytes

Por lo tanto, es perfectamente válido para enteros sin signo

En caso de discrepancias plzz informe

 -6
Author: ankit sablok,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-10-11 09:32:44