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

132

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

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

¿Es esta una buena forma portátil de lograr esto? ¿O está usando 0xffffffffo ~0mejor?

hiperlogico
fuente
1
No lo entiendo, ¿puedes explicarlo?
corazza
8
Creo que si el significado del código es claro es la pregunta más importante. Aunque -1siempre funcionará, el hecho de que se necesite un comentario después de que demuestre que no es un código claro. Si la variable está destinada a ser una colección de banderas, ¿por qué asignarle un número entero? Su tipo puede ser un entero, pero ciertamente no es semánticamente un entero. Nunca lo vas a incrementar o multiplicar. Por lo tanto, no lo usaría 0xffffffffpara portabilidad o corrección, sino para mayor claridad.
Cam Jackson
@CamJackson el comentario no es y cualquiera que escriba código C podría estar familiarizado con cómo se representan los valores.
Miles Rout
La pregunta originalmente fue etiquetada correctamente como C y C ++. Los lenguajes pueden ser divergentes en que C ++ tiene una propuesta para requerir el complemento de dos. Dicho esto, no cambia el hecho de que -1sigue siendo una solución portátil y compatible con versiones anteriores para ambos idiomas, pero podría afectar parte del razonamiento en otras respuestas.
Adrian McCarthy

Respuestas:

154

Le recomiendo que lo haga exactamente como lo ha mostrado, ya que es el más sencillo. Inicialice a -1lo que funcionará siempre , independientemente de la representación de signo real, mientras ~que a veces tendrá un comportamiento sorprendente porque tendrá que tener el tipo de operando correcto. Solo así obtendrá el valor más alto de un unsignedtipo.

Para un ejemplo de una posible sorpresa, considere este:

unsigned long a = ~0u;

No almacenará necesariamente 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 longtiene más bits es que no todos son 1.

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

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

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

Lo que debe entender es que 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 aal valor más alto posible es -1o UINT_MAX. El segundo dependerá del tipo de a- necesitará usar ULONG_MAXpara un unsigned long. Sin embargo, el primero no dependerá de su tipo, y es una buena manera de obtener el mayor valor.

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

Pero de lo que estamos hablando es de cuál es el resultado de la flagsvariable inicializada . Y para ello, solo-1 funcionará con todo tipo y máquina.

Johannes Schaub - litb
fuente
9
¿Por qué se garantiza que -1 se convertirá en todos? ¿Está garantizado por el estándar?
jalf
9
la conversión que ocurre es que agrega repetidamente uno más que ULONG_MAX hasta que esté dentro del rango (6.3.1.3 en el borrador C TC2). En C ++ es lo mismo, simplemente usando otra forma de formalización (módulo 2 ^ n). Todo se reduce a las relaciones matemáticas.
Johannes Schaub - litb
66
@litb: casting -1 es ciertamente una buena manera de obtener valores máximos sin signo, pero no es realmente descriptivo; esa es la razón por la que existen las constantes _MAX (SIZE_MAX se agregó en C99); concedido, la versión C ++ numeric_limits<size_t>::max()es un poco largo aliento, pero también lo es el elenco ...
Christoph
11
"No estamos hablando de si -1 tiene todos los bits uno (no siempre los tiene). Y no estamos hablando de si ~ 0 tiene todos los bits uno (los tiene, por supuesto)". - que ??? Pensé que el objetivo era establecer todos los bits en 1. Así es como funcionan las banderas ... ¿no? Miras los pedacitos . ¿A quién le importa el valor?
mpen
14
@Mark el interlocutor se preocupa. Él pregunta "¿Es seguro usar -1 para establecer todos los bits en verdadero". Esto no pregunta sobre qué bits -1está representado, ni pregunta qué bits ~0tiene. Puede que no nos interesen los valores, pero al compilador sí. No podemos ignorar el hecho de que las operaciones funcionan con y por valores. El valor de ~0puede no ser -1, pero este es el valor que necesita. Vea mi respuesta y el resumen de @ Dingo.
Johannes Schaub - litb
49
  • unsigned int flags = -1; Es portátil.
  • unsigned int flags = ~0; no es portátil porque se basa en una representación de complemento a dos.
  • unsigned int flags = 0xffffffff; no es portátil porque supone entradas de 32 bits.

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

Dingo
fuente
10
¿Cómo se basa ~ 0 (es decir, el operador del complemento de uno) en la representación del complemento de dos?
Drew Hall
11
Tienes esto al revés. Establece banderas a -1 que se basa en una representación de complemento a dos. En un signo + representación de magnitud menos uno solo tiene dos bits establecidos: el bit de signo y el bit menos significativo de la magnitud.
Stephen C. Steel
15
El estándar C requiere que el valor int de cero tenga su bit de signo y todos los bits de valor sean cero. Después del complemento de uno, todos esos bits son uno. Los valores de un int con todos los bits establecidos son: Signo y magnitud: INT_MIN Complemento de uno: -0 Complemento de dos: -1 Entonces, la declaración "unsigned int flags = ~ 0;" asignará el valor anterior que coincida con la representación entera de la plataforma. Pero el complemento '-1' de dos es el único que establecerá todos los bits de banderas en uno.
Dingo
9
@Stephen: De acuerdo con la representación. Pero cuando se asigna un valor int a un int sin signo, el sin signo no obtiene su valor adoptando la representación interna del valor int (excepto en los sistemas de complemento a dos donde eso generalmente funciona). Todos los valores asignados a int sin firmar son módulo (UINT_MAX + 1), por lo que asignar -1 funciona sin importar la representación interna.
Dingo
20
@ Mark: estás confundiendo dos operaciones. ~0produce un intvalor con todos los bits establecidos, por supuesto. Pero asignar un intan unsigned intno necesariamente da como resultado que el int sin signo tenga el mismo patrón de bits que el patrón de bits con signo. Solo con una representación de complemento a 2 es siempre este el caso. En un complemento de 1s o representación de magnitud de signo, la asignación de un intvalor negativo a un unsigned intresultado en un patrón de bits diferente. Esto se debe a que el estándar C ++ define la conversión con signo -> sin signo para que sea el valor de módulo igual, no el valor con los mismos bits.
Steve Jessop
25

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

Doug T.
fuente
Hay una serie de casos en los que no te importa tanto, pero son raros. Por ejemplo, algoritmos que funcionan en conjuntos de datos de N bits dividiéndolos en trozos de tamaño (sin signo) * CHAR_BIT bits cada uno.
MSalters
2
+1. Incluso si el tamaño del tipo de datos es mayor que el número de F (es decir, no configuró todos los bits como verdaderos), dado que está configurando explícitamente el valor, al menos sabe qué bits son "seguros" utilizar "..
mpen
17

Una forma de evitar los problemas mencionados es simplemente hacer:

unsigned int flags = 0;
flags = ~flags;

Portátil y al punto.

hammar
fuente
2
Pero luego pierdes la capacidad de declarar flagscomo const.
David Stone
1
@DavidStoneunsigned int const flags = ~0u;
@Zoidberg ': eso no funciona en sistemas que no sean el complemento de dos. Por ejemplo, en un sistema de magnitud de signo, ~0es un número entero que tiene todos los bits establecidos en 1, pero cuando lo asigna inta la unsignedvariable flags, realiza una conversión de valor de -2**31(suponiendo un 32 bits int) a (-2**31 % 2**32) == 2**31, que es un número entero con todos los bits excepto el primer set en 1.
David Stone
Esa es también una razón por la cual esta respuesta es peligrosa. Parece que la respuesta de @Zoidberg sería idéntica, pero en realidad no lo es. Sin embargo, como persona que lee el código, tendría que pensarlo para comprender por qué tomaste dos pasos para inicializarlo, y posiblemente sentir la tentación de cambiarlo a un solo paso.
David Stone
2
Ah sí, no noté el usufijo en tu respuesta. Eso, por supuesto, funcionaría, pero aún tiene el problema de especificar el tipo de datos que usa ( unsignedy no más grande) dos veces, lo que podría provocar errores. Sin embargo, es más probable que aparezca el error si la asignación y la declaración de variable inicial están más separadas.
David Stone
13

No estoy seguro de usar un unsigned int para banderas es una buena idea en primer lugar en C ++. ¿Qué pasa con bitset y similares?

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

Edouard A.
fuente
Me gusta esto por su estándar, pero es demasiado prolijo y te hace decir el tipo dos veces. Usar ~ 0 es probablemente más seguro ya que 0 puede ser cualquier tipo de entero. (Aunque sé que huele demasiado a C.)
Macke
El hecho de que sea prolijo puede verse como una ventaja. Pero también me gusta ~ 0.
Edouard A.
2
Puede mitigar la palabrería con la macro estándar UINT_MAX, ya que de todos modos está codificando el tipo unsigned int.
2
@Macke Puede evitar indicar el tipo en C ++ 11 con auto. auto const flags = std::numeric_limit<unsigned>::max().
David Stone
11
unsigned int flags = -1;  // all bits are true

"¿Es esta una buena forma portátil de lograr esto?"

¿Portátil? .

¿Bueno? Debatible , como lo demuestra toda la confusión que se muestra 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 las advertencias del compilador . Para eludir la advertencia sin paralizar su compilador, necesitaría un reparto explícito. Por ejemplo,

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

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

Mi consejo sería prestar atención al tipo de destino y asegurarse de que no haya 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);

Todo lo cual es correcto y más obvio para sus compañeros programadores.

Y con C ++ 11 : podemos usar autopara simplificar cualquiera de estos:

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.

Adrian McCarthy
fuente
10

La conversión de -1 en cualquier tipo sin signo está garantizada por el estándar para dar como resultado todos. El uso de ~0Ues generalmente malo ya que 0tiene tipo unsigned inty 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, ~0deberí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 0xffffffffsi sabe que necesita exactamente 32 bits, pero -1 tiene la ventaja de que funcionará en cualquier contexto, incluso si no conoce el tamaño del tipo, como las macros que funcionan en varios tipos , o si el tamaño del tipo varía según la implementación. Si lo hace saber el tipo, otra forma segura de obtener todos unos macros es el límite UINT_MAX, ULONG_MAX, ULLONG_MAX, etc.

Personalmente siempre uso -1. Siempre funciona y no tienes que pensarlo.

R .. GitHub DEJA DE AYUDAR AL HIELO
fuente
FWIW, si me refiero a "todos los 1 bits" que uso ~(type)0(bueno, complete el derecho, typepor supuesto). Lanzar cero todavía da como resultado un cero, por lo que está claro, y negar todos los bits en el tipo de destino está claramente definido. Sin embargo, no es tan frecuente que realmente quiera esa operación; YMMV.
Donal Fellows
66
@Donal: simplemente estás equivocado. C especifica que, al convertir un valor que no cabe en un tipo sin signo, los valores se reducen en el módulo 2 ^ n donde n es el número de bits en el tipo de destino. Esto se aplica tanto a los valores con signo como a los tipos sin signo más grandes. No tiene nada que ver con el complemento de dos.
R .. GitHub DEJA DE AYUDAR AL HIELO
2
Ellos lo hacen en práctica la misma, lo que es trivial; solo usa un código de operación de resta sin signo en lugar de uno firmado o una neginstrucción. Las máquinas que tienen un comportamiento aritmético con signo falso tienen códigos opcionales aritméticos con signo / sin signo. Por supuesto, un compilador realmente bueno ignoraría siempre los códigos de operación firmados incluso para los valores firmados y, por lo tanto, obtendría dos complementos de forma gratuita.
R .. GitHub DEJA DE AYUDAR AL HIELO
1
@R .: El var = ~(0*var)caso fallará por varser un tipo sin signo más estrecho que int. Tal vez var = ~(0U*var)? (Personalmente, todavía prefiero -1, sin embargo).
caf
1
Esta respuesta es mucho más clara que la de Johannes Schaub. Sin embargo, la asignación de un entero literal negativo a un tipo sin signo sin conversión suele generar una advertencia del compilador. La supresión de la advertencia requiere un reparto, lo que significa tener que prestar atención al tipo de objetivo de todos modos, por lo que también puede usar UINT_MAX o ULONG_MAX y ser claro en lugar de confiar en un pequeño detalle en el estándar que claramente confunde a muchos de sus compañeros programadores. .
Adrian McCarthy
5

Siempre que tenga #include <limits.h>uno de sus incluidos, solo debe usar

unsigned int flags = UINT_MAX;

Si quieres un poco de bits, puedes usar

unsigned long flags = ULONG_MAX;

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

Michael Norrish
fuente
1
las constantes que sugirió están definidas en los límites. h - stdint.h contiene los límites para los tipos de enteros adicionales (enteros de tamaño fijo, intptr_t, ...)
Christoph
5

Si. Como se menciona en otras respuestas, -1es el más portátil; sin embargo, no es muy semántico y activa advertencias del compilador.

Para resolver estos problemas, pruebe este simple ayudante:

static const struct All1s
{
    template<typename UnsignedType>
    inline operator UnsignedType(void) const
    {
        static_assert(std::is_unsigned<UnsignedType>::value, "This is designed only for unsigned types");
        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;
Pitón Diamante
fuente
3
Como programador en C, un código como este me da pesadillas por la noche.
jforberg
¿Y qué sucede cuando usas esto en un contexto como ALL_BITS_TRUE ^ adonde aestá un entero con signo? El tipo permanece entero con signo y el patrón de bits (representación de objeto) depende de que el objetivo sea el complemento de 2 o no.
Peter Cordes
No, ALL_BITS_TRUE ^ ada un error de compilación porque ALL_BITS_TRUEes ambiguo. Podría ser utilizado como uint32_t(ALL_BITS_TRUE) ^ a, sin embargo. Puede probarlo usted mismo en cpp.sh :) Hoy en día agregaría un static_assert(std::is_unsigned<UnsignedType>::value, "This is designed only for unsigned types");en el operatorpara asegurarse de que los usuarios no intenten usarlo int(ALL_BITS_TRUE). Actualizaré la respuesta.
Diamond Python
3

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

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

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

Además, si realmente se preocupan por los bits individuales en una vairable, sería una buena idea para empezar a utilizar el ancho fijo uint8_t, uint16_t, uint32_ttipos.

myron-semack
fuente
2

En los procesadores Intel IA-32 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 elementos inmediatos de 32 bits. En las instrucciones de 64 bits, los inmediatos de 32 bits se extienden por signos 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 coloca 32 1s en la parte inferior de RAX (también conocido como EAX):

mov eax, 0ffffffffh

Y, de hecho, he tenido errores en los programas cuando quería escribir 0xffffffff en una variable de 64 bits y obtuve un 0xffffffffffffffff en su lugar. 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 tanta gente lo respondió que pensé que lo agregaría como una respuesta separada.

Nathan Fellman
fuente
1
¡Felicitaciones, has encontrado un error de compilación!
tc.
¿Se ha documentado esto en algún lugar como un error?
Nathan Fellman
1
Suponiendo que se UINT64_C(0xffffffff)expande a algo así 0xffffffffuLL, definitivamente es un error del compilador. El estándar C analiza en gran medida los valores , el valor representado por 0xffffffffes 4294967295 (no 36893488147419103231), y no hay conversiones a tipos enteros con signo a la vista.
tc.
2

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

Mi desacuerdo es que, 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 que dos a la potencia del número de bits' como todos los bits configurados, 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 sistema de numeración binaria puro. [Nota 44:] Una representación posicional para enteros que usa los dígitos binarios 0 y 1, en los 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 por el bit con La posición más alta.

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

James Hopkin
fuente
En general, no podemos estar seguros sobre el valor de los bits de relleno. Y si queremos, entonces podríamos estar en peligro ya que podríamos generar una representación de trampa para ellos (y podría generar señales). Sin embargo, el estándar requiere que el carácter sin signo no tenga bits de relleno, y en 4.7 / 2 en el estándar c ++ dice que al convertir un entero a un tipo sin signo, el valor de la variable sin signo resultante es el valor más pequeño congruente con el valor entero de origen, (módulo 2 ^ n, n == número de bits en el tipo sin signo). entonces (-1) == ((2 ^ n) -1) (mod 2 ^ n). 2 ^ n-1 tiene todos los bits establecidos en un sistema de numeración binario puro.
Johannes Schaub - litb
Si realmente queremos tener todos los bits 1 en la representación de objetos de un tipo sin signo, necesitaríamos memset. Pero podríamos generar una representación de trampa de este modo :( De todos modos, una implementación probablemente no tiene razón para tirar un poco de sus enteros sin signo, por lo que la usará para almacenar sus valores. Pero tiene un muy buen punto: no hay nada que se detenga una interpretación de tener algunas tonterías tontas, creo (aparte de en char / char firmado / unsigned char, que no debe tener esos). +1 por supuesto :)
Johannes Schaub - litb
Al final, creo que el estándar podría ser más claro a qué representación se refiere en 4.7 / 2. Si se refiere a la representación del objeto, entonces ya no hay lugar para los bits de relleno (he visto personas discutiendo así, con lo que no veo nada malo). Pero creo que habla de la representación del valor (porque todo en 4.7 / 2 trata de valores de todos modos, y luego los bits de relleno pueden anidar junto a los bits de valor.
Johannes Schaub - litb
1
El estándar parece tener claramente representaciones de 'complemento de 2, complemento de 1 y magnitud firmada' en mente, pero no quiere descartar nada. Punto interesante sobre la captura de representaciones también. Por lo que puedo decir, el bit que cité es la definición de 'sistema de numeración binaria puro' en lo que respecta al Estándar: el bit 'excepto' al final es realmente mi única duda sobre si el lanzamiento de -1 está garantizado trabajo.
James Hopkin
2

Aunque el 0xFFFF(o 0xFFFFFFFF, etc.) puede ser más fácil de leer, puede romper la portabilidad del 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 especificados por la persona que llama). La rutina puede ser totalmente agnóstica en cuanto a lo que representan los bits, pero aún debe tener una constante de "todos los bits establecidos". En tal caso, -1 será mucho mejor que una constante hexadecimal ya que funcionará con cualquier tamaño de bit.

La otra posibilidad, si typedefse usa un valor para la máscara de bits, sería usar ~ (bitMaskType) 0; Si la máscara de bits es solo un tipo de 16 bits, esa expresión solo tendrá 16 bits establecidos (incluso si 'int' sería de otro modo 32 bits) pero dado que 16 bits serán todo lo que se requiere, las cosas deberían estar bien siempre que en realidad usa el tipo apropiado en el typecast.

Por cierto, las expresiones de la forma longvar &= ~[hex_constant]tienen un problema desagradable si la constante hexadecimal es demasiado grande para caber en un int, pero encajará en un unsigned int. Si an intes de 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 inttendrán el operador del complemento aplicado a un tipo int, pero el resultado se extenderá a long, configurando los bits superiores. Los valores que son demasiado grandes unsigned inttendrán el operador del complemento aplicado al tipo long. Sin embargo, los valores que se encuentran entre esos tamaños aplicarán el operador de complemento al tipo unsigned int, que luego se convertirá a tipo longsin extensión de signo.

Super gato
fuente
1

Prácticamente: si

Teóricamente: no.

-1 = 0xFFFFFFFF (o cualquier tamaño que tenga un int en su plataforma) solo es cierto con la aritmética del complemento a 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 a dos. Su solución ~ 0 propuesta debería funcionar en todas partes.

Drew Hall
fuente
66
Yo también dije eso. Pero luego me di cuenta de que estaba equivocado, ya que -1 con signo siempre se convierte en max_value sin signo según las reglas de conversión, independientemente de las representaciones de valor. Al menos, lo hace en C ++, no tengo el estándar C a mano.
Steve Jessop el
66
Hay una ambigüedad. -1 no es 0xFFFFFFFF. Pero -1 es 0xFFFFFFFF si se convierte en un int sin signo (que tiene 32 bits). Eso es lo que hace que esta discusión sea tan difícil, creo. Muchas personas tienen en mente cosas muy diferentes cuando hablan de esas cadenas de bits.
Johannes Schaub - litb
1

Como otros han mencionado, -1 es la forma correcta de crear un número entero que se convertirá en 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::bitsetcon todos los bits establecidos en 1 por las mismas razones mencionadas en otras respuestas.

David Stone
fuente
0

Ciertamente es seguro, ya que -1 siempre tendrá todos los bits disponibles, 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.

Zifre
fuente
44
"0xFF ... no es bueno porque depende del ancho del tipo" Creo que es la única forma sensata de hacerlo. Se supone que debes definir claramente qué significa cada bandera / bit en tu programa. Entonces, si define que está utilizando los 32 bits más bajos para almacenar banderas, debe restringirse a usar esos 32 bits, ya sea que el tamaño real de la int sea 32 o 64.
Juan Pablo Califano
0

Yo digo:

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

Esto siempre te dará el resultado deseado.

Alex
fuente
44
¡No en sistemas con caracteres de 9 bits!
tc.
0

Aprovechar 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 extender el alcance de la pregunta a todos los tipos enteros sin signo:

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

Como alternativa, para C ++, puede:

  1. Incluir <limits>y usarstd::numeric_limits< your_type >::max()
  2. Escriba una función de plantilla personalizada (Esto también permitiría alguna 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 la asignación -1siempre necesitaría algún comentario explicativo.

Antonio
fuente
0

Una forma de hacer que el significado sea un poco más obvio y, sin embargo, evitar repetir el tipo:

const auto flags = static_cast<unsigned int>(-1);
FlorianH
fuente
-6

Sí, la representación mostrada es muy correcta, ya que si lo hacemos al revés, requerirá que un operador invierta 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 número entero es de 2 bytes = el valor máximo de 16 bits 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 las clases de residuos mod 65536) por lo tanto es mucho sencillo

supongo

no, si considera esta noción, es perfectamente ideal para entradas sin signo y realmente funciona

solo verifique el siguiente fragmento de programa

int main () {

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 que es -1% 2 ^ 32 en enteros de 4 bytes

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

en caso de discrepancias, por favor informe

Ankit Sablok
fuente
9
Dos comentarios: primero, estás completamente equivocado sobre el tamaño de los enteros en "la mayoría" de las máquinas. En segundo lugar, ur txt es muy difícil 2 leer debido a 2 ur de suma tipo de lenguaje seckrit. Por favor, usen inglés simple .
Konrad Rudolph el