É seguro usar -1 para definir todos os bits como verdadeiros?

132

Eu já vi esse padrão usado muito em C & C ++.

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

Essa é uma boa maneira portátil de fazer isso? Ou está usando 0xffffffffou ~0melhor?

hiperlógico
fonte
1
Eu não entendo, você pode explicar?
Corazza
8
Eu acho que se o significado do código é claro é a questão mais importante. Mesmo que -1sempre funcione, o fato de ser necessário um comentário depois de mostrar que não é um código claro. Se a variável pretende ser uma coleção de sinalizadores, por que atribuí-la um número inteiro? Seu tipo pode ser um número inteiro, mas certamente não é semanticamente um número inteiro. Você nunca vai incrementá-lo ou multiplicá-lo. Então, eu usaria 0xffffffffnão para portabilidade ou correção, mas para maior clareza.
amigos estão dizendo sobre cam
@CamJackson o comentário não é e qualquer pessoa que esteja escrevendo código C pode estar familiarizado com a forma como os valores são representados.
Rota de milhas
A questão foi originalmente marcada como C e C ++. Os idiomas podem divergir, pois o C ++ tem uma proposta para exigir o complemento de dois. Dito isso, ele não altera o fato de que -1continua a ser uma solução portátil e compatível com versões anteriores dos dois idiomas, mas pode afetar parte do raciocínio de outras respostas.
Adrian McCarthy

Respostas:

154

Eu recomendo que você faça exatamente como demonstrou, pois é o mais direto. Inicialize para o -1qual sempre funcionará , independentemente da representação real do sinal, enquanto ~às vezes terá um comportamento surpreendente, pois você precisará ter o tipo certo de operando. Somente então você obterá o valor mais alto de um unsignedtipo.

Para um exemplo de uma possível surpresa, considere este:

unsigned long a = ~0u;

Não necessariamente armazenará um padrão com todos os bits 1 a. Mas ele primeiro criará um padrão com todos os bits 1 em um unsigned inte depois o atribuirá a. O que acontece quando unsigned longhá mais bits é que nem todos são 1.

E considere este, que falhará na representação do complemento de um não-dois:

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

A razão para isso é que ~0é necessário inverter todos os bits. Invertendo que irá produzir -1na máquina de complemento de dois (que é o valor que precisamos!), Mas não deu -1em outra representação. Na máquina de complemento de uma pessoa, ela produz zero. Assim, na máquina de complemento de uma pessoa, o acima será inicializado acomo zero.

O que você deve entender é que se trata de valores - não de bits. A variável é inicializada com um valor . Se no inicializador você modificar os bits da variável usada para inicialização, o valor será gerado de acordo com esses bits. O valor que você precisa, para inicializar acom o maior valor possível, é -1ou UINT_MAX. O segundo dependerá do tipo de a- você precisará usar ULONG_MAXpara um unsigned long. No entanto, o primeiro não dependerá do seu tipo e é uma ótima maneira de obter o valor mais alto.

Estamos não falar sobre se -1tem todos os bits um (que nem sempre tem). E nós estamos não falar sobre se ~0tem todos os bits um (ele tem, é claro).

Mas o que estamos falando é qual é o resultado da flagsvariável inicializada . E, para isso, apenas-1 funcionará com todos os tipos e máquinas.

Johannes Schaub - litb
fonte
9
por que -1 é garantido para ser convertido em todos? Isso é garantido pelo padrão?
jalf
9
a conversão que ocorre é que ele adiciona repetidamente mais um que ULONG_MAX até que esteja dentro do intervalo (6.3.1.3 no rascunho do C TC2). Em C ++ é o mesmo, apenas usando outra maneira de formalizá-lo (módulo 2 ^ n). Tudo se resume a relações matemáticas.
Johannes Schaub - litb
6
@litb: casting -1 é certamente uma boa maneira de obter valores máximos não assinados, mas não é realmente descritivo; essa é a razão pela qual as constantes _MAX existem (SIZE_MAX foi adicionado em C99); concedida, a versão do C ++ numeric_limits<size_t>::max()é um pouco prolixo, mas assim é o elenco ...
Christoph
11
"Não estamos falando sobre se -1 possui todos os bits um (nem sempre). E não estamos falando sobre se ~ 0 possui todos os bits um (é claro)." - o que ??? Eu pensei que o objetivo era definir todos os bits como 1. É assim que as bandeiras funcionam .. não? Você olha para os bits . Quem se importa com o valor?
fácil
14
@ Mark o interlocutor se importa. Ele pergunta "É seguro usar -1 para definir todos os bits como verdadeiros". Isso não pergunta sobre quais bits -1são representados por nem bits ~0. Podemos não nos importar com valores, mas o compilador sim. Não podemos ignorar o fato de que as operações funcionam com e por valores. O valor de ~0pode não ser -1, mas esse é o valor que você precisa. Veja minha resposta e o resumo do @ Dingo.
Johannes Schaub - litb 2/08/10
49
  • unsigned int flags = -1; é portátil.
  • unsigned int flags = ~0; não é portátil porque depende de uma representação de complemento de dois.
  • unsigned int flags = 0xffffffff; não é portátil porque assume entradas de 32 bits.

Se você deseja definir todos os bits de uma maneira garantida pelo padrão C, use o primeiro.

Dingo
fonte
10
Como ~ 0 (ou seja, o operador de complemento de alguém) depende da representação de complemento de dois?
Drew Hall
11
Você tem isso ao contrário. Sua configuração sinaliza para -1, que depende de uma representação de dois complementos. Em uma representação sinal + magnitude menos um só tem dois bits definidos: o bit do sinal e o bit menos significativo da magnitude.
223 Stephen C. Steel
15
O padrão C requer que o valor int de zero tenha seu bit de sinal e todos os bits de valor sejam zero. Depois do complemento, todos esses bits são um. Os valores de um int com todos os bits definidos são: Sinal e magnitude: INT_MIN Complemento de um: -0 Complemento de dois: -1 Portanto, a instrução "unsigned int flags = ~ 0;" atribuirá o valor acima que corresponda à representação inteira da plataforma. Mas o complemento '-1' de dois é o único que definirá todos os bits de sinalizadores para um.
Dingo
9
@ Stephen: concordou com a representação. Mas quando um valor int é atribuído a um int não assinado, o não assinado não obtém seu valor adotando a representação interna do valor int (exceto nos sistemas de complemento de dois, onde geralmente funciona). Todos os valores atribuídos a int não assinados são modulo (UINT_MAX + 1), portanto, atribuir -1 funciona independentemente da representação interna.
Dingo
20
@ Mark: você está confundindo duas operações. ~0gera um intvalor com todos os bits definidos, é claro. Mas atribuir um inta um unsigned intnão resulta necessariamente no int não assinado tendo o mesmo padrão de bits que o padrão de bits assinado. Somente com a representação do complemento de 2 é esse sempre o caso. Na representação de complemento ou magnitude de sinal de 1s, atribuir um intvalor negativo a um unsigned intresultado em um padrão de bits diferente. Isso ocorre porque o padrão C ++ define conversão assinada -> não assinada como o valor igual a módulo, não o valor com os mesmos bits.
18710 Steve
25

Francamente, acho que todos os fff's são mais legíveis. Quanto ao comentário de que é um antipadrão, se você realmente se importa que todos os bits estejam configurados / limpos, eu diria que você provavelmente está em uma situação em que se importa com o tamanho da variável de qualquer maneira, o que exigiria algo como aumento :: uint16_t, etc.

Doug T.
fonte
Existem vários casos em que você não se importa muito, mas eles são raros. Por exemplo, algoritmos que funcionam em conjuntos de dados de N bits, dividindo-os em pedaços de sizeof (sem sinal) * CHAR_BIT bits cada.
MSalters
2
+1. Mesmo que o tamanho do tipo de dados seja maior que o número de Fs (ou seja, você não definiu todos os bits como verdadeiros), já que você está definindo explicitamente o valor, pelo menos sabe quais bits são "seguros" usar "..
mpen
17

Uma maneira de evitar os problemas mencionados é simplesmente fazer:

unsigned int flags = 0;
flags = ~flags;

Portátil e direto ao ponto.

hammar
fonte
2
Mas então você perde a capacidade de declarar flagscomo const.
1811 David Stone
1
@DavidStoneunsigned int const flags = ~0u;
@Zoidberg '- Isso não funciona em sistemas que não sejam o complemento de dois. Por exemplo, em um sistema de magnitude de sinal, ~0é um número inteiro que possui todos os bits definidos como 1, mas quando você o atribui intà unsignedvariável flags, realiza uma conversão de valor de -2**31(assumindo 32 bits int) para (-2**31 % 2**32) == 2**31, que é um número inteiro com todos os bits, exceto o primeiro, definido como 1. #
1113 David Stone
Essa também é uma razão pela qual essa resposta é perigosa. Parece que a resposta de @Zoidberg '- seria idêntica, mas na verdade não é. No entanto, como uma pessoa que lê o código, eu teria que pensar sobre isso para entender por que você deu dois passos para inicializá-lo e, possivelmente, seria tentado a mudar isso para um único passo.
David Stone
2
Ah sim, eu não notei o usufixo na sua resposta. Obviamente, isso funcionaria, mas ainda tem o problema de especificar o tipo de dados que você usa ( unsignede não é maior) duas vezes, o que pode levar a erros. O erro provavelmente aparecerá se a atribuição e a declaração inicial da variável estiverem mais distantes.
David Stone
13

Não tenho certeza de que usar um int não assinado para sinalizadores seja uma boa idéia em primeiro lugar em C ++. E quanto ao bitset e afins?

std::numeric_limit<unsigned int>::max()é melhor porque 0xffffffffassume que int não assinado é um número inteiro de 32 bits.

Edouard A.
fonte
Eu gosto disso por causa de seu padrão, mas é muito prolixo e faz você indicar o tipo duas vezes. Usar ~ 0 é provavelmente mais seguro, pois 0 pode ser qualquer tipo de número inteiro. (Embora eu saiba que cheira muito de C.)
Macke
O fato de ser prolixo pode ser visto como uma vantagem. Mas eu gosto de ~ 0 também.
Edouard A.
2
Você pode atenuar a verbosidade com a macro UINT_MAX padrão, pois está codificando o tipo unsigned int de qualquer maneira.
2
@ Macke Você pode evitar indicar o tipo em C ++ 11 com auto. auto const flags = std::numeric_limit<unsigned>::max().
David Stone
11
unsigned int flags = -1;  // all bits are true

"Essa é uma boa maneira portátil de fazer isso?"

Portátil? Sim .

Boa? Debatível , como evidenciado por toda a confusão mostrada neste tópico. Ser claro o suficiente para que seus colegas programadores possam entender o código sem confusão deve ser uma das dimensões que medimos para obter um bom código.

Além disso, esse método é propenso a avisos do compilador . Para eliminar o aviso sem danificar seu compilador, você precisa de uma conversão explícita. Por exemplo,

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

A conversão explícita exige que você preste atenção ao tipo de destino. Se você está prestando atenção ao tipo de alvo, evita naturalmente as armadilhas das outras abordagens.

Meu conselho seria prestar atenção ao tipo de destino e garantir que não haja conversões implícitas. Por exemplo:

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 os quais são corretos e mais óbvios para seus colegas programadores.

E com o C ++ 11 : podemos usar autopara tornar ainda mais simples:

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

Considero correto e óbvio melhor do que simplesmente correto.

Adrian McCarthy
fonte
10

A conversão de -1 em qualquer tipo não assinado é garantida pelo padrão para resultar em todos. O uso de ~0Ugeralmente é ruim, pois 0tem tipo unsigned inte não preenche todos os bits de um tipo maior não assinado, a menos que você escreva explicitamente algo como ~0ULL. Em sistemas sãos, ~0deve ser idêntico a -1, mas como o padrão permite representações de complemento de unidades e sinal / magnitude, estritamente falando, não é portátil.

É claro que é sempre bom escrever 0xffffffffse você sabe que precisa exatamente de 32 bits, mas -1 tem a vantagem de funcionar em qualquer contexto, mesmo quando você não conhece o tamanho do tipo, como macros que funcionam em vários tipos ou se o tamanho do tipo variar de acordo com a implementação. Se você não sabe o tipo, outra forma segura de obter todo-queridos é as macros limite UINT_MAX, ULONG_MAX, ULLONG_MAX, etc.

Pessoalmente eu sempre uso -1. Sempre funciona e você não precisa pensar nisso.

R .. GitHub PARE DE AJUDAR GELO
fonte
FWIW, se eu quero dizer “todos os 1 bits” que eu uso ~(type)0(bem, preencha o que está certo, é typeclaro). A conversão de zero ainda resulta em zero, então isso é claro, e a negação de todos os bits no tipo de destino é claramente definida. Não é tão frequente que eu realmente queira essa operação; YMMV.
Donal Fellows
6
@Donal: você está simplesmente errado. C especifica que, ao converter um valor que não se encaixa em um tipo não assinado, os valores são reduzidos no módulo 2 ^ n onde n é o número de bits no tipo de destino. Isso se aplica aos valores assinados e aos tipos não assinados maiores. Não tem nada a ver com o complemento de dois.
R .. GitHub Pare de ajudar o gelo
2
Eles fazem implementá-lo o mesmo, o que é trivial; você apenas usa um código de operação de subtração não assinado em vez de um assinado ou uma neginstrução. Máquinas com comportamento aritmético com sinal falso têm opcodes aritméticos com sinal / sem sinal separados. É claro que um compilador realmente bom sempre ignoraria os códigos de operação assinados, mesmo para valores assinados, e assim obteria dois complementos gratuitamente.
R .. GitHub Pare de ajudar o gelo
1
@R .: O var = ~(0*var)caso falhará por varser um tipo não assinado mais estreito que int. Talvez var = ~(0U*var)? (pessoalmente ainda prefiro -1).
Caf
1
Essa resposta é muito mais clara que a de Johannes Schaub. No entanto, atribuir um número inteiro literal negativo a um tipo não assinado sem uma conversão geralmente resulta em um aviso do compilador. Suprimir o aviso requer uma conversão, o que significa que você deve prestar atenção ao tipo de destino de qualquer maneira, portanto, você também pode usar UINT_MAX ou ULONG_MAX e ser claro, em vez de confiar em um pequeno detalhe no padrão, o que claramente confunde muitos de seus colegas programadores. .
Adrian McCarthy
5

Contanto que você tenha #include <limits.h>uma de suas inclusões, use apenas

unsigned int flags = UINT_MAX;

Se você quiser um valor de bits longo, poderá usar

unsigned long flags = ULONG_MAX;

É garantido que esses valores tenham todos os bits de valor do resultado definidos como 1, independentemente de como números inteiros assinados sejam implementados.

Michael Norrish
fonte
1
as constantes você sugeridas são realmente definido na limits.h - stdint.h contém os limites para os tipos inteiros adicionais (-fixados porte inteiros, intptr_t, ...)
Christoph
5

Sim. Como mencionado em outras respostas, -1é o mais portátil; no entanto, não é muito semântico e dispara avisos do compilador.

Para resolver esses problemas, tente este simples auxiliar:

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;
Diamond Python
fonte
3
Como programador em C, códigos como esse me dão pesadelos à noite.
jforberg
E o que acontece quando você usa isso em um contexto como ALL_BITS_TRUE ^ aonde aestá um número inteiro assinado? O tipo permanece com número inteiro assinado e o padrão de bits (representação do objeto) depende do destino ser o complemento de 2 ou não.
Peter Cordes
Não, ALL_BITS_TRUE ^ agera um erro de compilação porque ALL_BITS_TRUEé ambíguo. Poderia ser usado como uint32_t(ALL_BITS_TRUE) ^ a, no entanto. Você pode experimentar por si mesmo em cpp.sh :) Hoje em dia eu adicionar um static_assert(std::is_unsigned<UnsignedType>::value, "This is designed only for unsigned types");no operatorpara ter certeza de que os usuários não tentar usar int(ALL_BITS_TRUE). Vou atualizar a resposta.
Diamond Python
3

Eu não faria a coisa -1. É bastante não intuitivo (pelo menos para mim). Atribuir dados assinados a uma variável não assinada apenas parece ser uma violação da ordem natural das coisas.

Na sua situação, eu sempre uso 0xFFFF. (Use o número certo de Fs para o tamanho variável, é claro.)

[BTW, raramente vejo o truque -1 feito no código do mundo real.]

Além disso, se você realmente se preocupam com os bits individuais em um vairable, seria boa idéia para começar a usar a largura fixa uint8_t, uint16_t, uint32_ttipos.

myron-semack
fonte
2

Nos processadores IA-32 da Intel, não há problema em gravar 0xFFFFFFFF em um registro de 64 bits e obter os resultados esperados. Isso ocorre porque o IA32e (a extensão de 64 bits para o IA32) suporta apenas imediatos de 32 bits. Nas instruções de 64 bits, os imediatos de 32 bits são estendidos para 64 bits.

O seguinte é ilegal:

mov rax, 0ffffffffffffffffh

O seguinte coloca 64 1s em RAX:

mov rax, 0ffffffffh

Apenas para completar, o seguinte coloca 32 1s na parte inferior do RAX (aka EAX):

mov eax, 0ffffffffh

E, de fato, tive programas falhar quando quis escrever 0xffffffff em uma variável de 64 bits e, em vez disso, recebi um 0xffffffffffffffff. Em C, isso seria:

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

o resultado é:

x is 0xffffffffffffffff

Eu pensei em postar isso como um comentário em todas as respostas que diziam que 0xFFFFFFFF assume 32 bits, mas muitas pessoas responderam que eu achei que adicionaria como resposta separada.

Nathan Fellman
fonte
1
Parabéns, você encontrou um bug do compilador!
tc.
Isso foi documentado em algum lugar como um bug?
10134 Nathan Fellman
1
Supondo que se UINT64_C(0xffffffff)expanda para algo como 0xffffffffuLL, é definitivamente um bug do compilador. O padrão C discute amplamente valores , o valor representado por 0xffffffffé 4294967295 (não 36893488147419103231) e não há conversões para tipos inteiros assinados à vista.
tc.
2

Veja a resposta do litb para uma explicação muito clara dos problemas.

Meu desacordo é que, estritamente falando, não há garantias para nenhum dos casos. Não conheço nenhuma arquitetura que não represente um valor não assinado de 'um a menos do que dois à potência do número de bits' como todos os bits configurados, mas aqui está o que o Padrão realmente diz (3.9.1 / 7 mais nota 44):

As representações dos tipos integrais devem definir valores usando um sistema de numeração binária pura. [Nota 44:] Uma representação posicional para números inteiros que usa os dígitos binários 0 e 1, na qual os valores representados por bits sucessivos são aditivos, começam com 1 e são multiplicados pela potência integral sucessiva de 2, exceto talvez para o bit com a posição mais alta.

Isso deixa a possibilidade de um dos bits ser qualquer coisa.

James Hopkin
fonte
Em geral, não podemos ter certeza sobre o valor dos bits de preenchimento. E se quisermos, poderíamos estar em perigo, pois poderíamos gerar uma representação de armadilha para eles (e isso poderia gerar sinais). No entanto, o std exige que char não assinado não tenha bits de preenchimento e, em 4,7 / 2 no padrão c ++, diz que, convertendo um número inteiro em um tipo não assinado, o valor da variável não assinada resultante é o menor valor congruente com o valor inteiro de origem, (módulo 2 ^ n, n == número de bits no tipo não assinado). então (-1) == ((2 ^ n) -1) (mod 2 ^ n). 2 ^ n-1 tem todos os bits configurados em um sistema de numeração binária pura.
Johannes Schaub - litb
Se realmente quisermos ter todos os bits 1 na representação do objeto de um tipo não assinado, precisaríamos do memset. Mas poderíamos gerar uma representação de interceptação da seguinte maneira :( De qualquer forma, uma implementação provavelmente não tem motivos para jogar um pouco fora de seus números inteiros não assinados, portanto ela será usada para armazenar seus valores. Mas você tem um ponto muito bom - não há nada parando uma interpretação de ter alguns pedaços sem sentido parvo, eu acho que (além de no caractere / char assinado / unsigned char, que não deve ter aqueles) +1 é claro :).
Johannes Schaub - litb
No final, acho que o padrão poderia ser mais claro a que representação se refere em 4.7 / 2. Se se refere à representação do objeto, então não há mais lugar para preenchimento de bits (já vi pessoas discutindo assim com as quais não vejo nada de errado). Mas eu acho que ele fala sobre a representação de valor (porque tudo em 4.7 / 2 é sobre valores de qualquer maneira - e, em seguida, os bits de preenchimento podem se aninhar ao lado dos bits de valor.
Johannes Schaub - litb 12/09/09
1
O Padrão parece claramente ter em mente as representações 'complemento 2, complemento 1 e magnitude assinada', mas não quer descartar nada. Ponto interessante sobre capturar representações também. Tanto quanto posso dizer, o bit que citei é a definição de 'sistema de numeração binária pura' no que diz respeito ao Padrão - o bit 'exceto' no final é realmente minha única dúvida sobre se a conversão de -1 é garantida. trabalhos.
1211 James Hopkin
2

Embora o 0xFFFF(ou 0xFFFFFFFFetc.) possa ser mais fácil de ler, ele pode quebrar a portabilidade no código que, de outra forma, seria portátil. Considere, por exemplo, uma rotina de biblioteca para contar quantos itens em uma estrutura de dados possuem determinados bits definidos (os bits exatos sendo especificados pelo chamador). A rotina pode ser totalmente independente do que os bits representam, mas ainda precisa ter uma constante "todos os bits definidos". Nesse caso, -1 será muito melhor que uma constante hexadecimal, pois funcionará com qualquer tamanho de bit.

A outra possibilidade, se um typedefvalor for usado para a máscara de bits, seria usar ~ (bitMaskType) 0; se a máscara de bits for apenas do tipo de 16 bits, essa expressão terá apenas 16 bits definidos (mesmo que 'int' seja de 32 bits), mas como 16 bits serão tudo o que é necessário, as coisas devem ficar bem, desde que uma realmente usa o tipo apropriado no typecast.

Aliás, as expressões do formulário longvar &= ~[hex_constant]têm uma pegadinha desagradável se a constante hexadecimal for muito grande para caber em um int, mas caberá em um unsigned int. Se um inttiver 16 bits, então longvar &= ~0x4000;ou longvar &= ~0x10000; limpará um bit de longvar, mas longvar &= ~0x8000;limpará o bit 15 e todos os bits acima dele. Os valores que se encaixam intterão o operador de complemento aplicado a um tipo int, mas o resultado será estendido para o sinal long, configurando os bits superiores. Valores grandes demais unsigned intterão o operador de complemento aplicado ao tipo long. Valores entre esses tamanhos, no entanto, aplicarão o operador complemento ao tipo unsigned int, que será convertido em tipo longsem extensão de sinal.

supercat
fonte
1

Praticamente: Sim

Teoricamente: Não.

-1 = 0xFFFFFFFF (ou qualquer que seja o tamanho de um int em sua plataforma) só é verdadeiro com a aritmética de complemento de dois. Na prática, funcionará, mas existem máquinas legadas por aí (mainframes da IBM etc.) nas quais você tem um bit de sinal real em vez da representação de complemento de dois. Sua solução proposta ~ 0 deve funcionar em qualquer lugar.

Drew Hall
fonte
6
Eu disse isso também. Mas então percebi que estava errado, já que -1 assinado sempre se converte em max_value sem sinal sob as regras de conversão, independentemente das representações de valor. Pelo menos, em C ++, não tenho o padrão C à mão.
30510 Steve Steveop
6
existe uma ambiguidade. -1 não é 0xFFFFFFFF. Mas -1 é 0xFFFFFFFF se convertido em um int sem sinal (com 32 bits). É isso que está dificultando a discussão. Muitas pessoas têm coisas muito diferentes em mente quando falam sobre essas seqüências de bits.
Johannes Schaub - litb
1

Como outros já mencionaram, -1 é a maneira correta de criar um número inteiro que será convertido em um tipo não assinado com todos os bits definidos como 1. No entanto, o mais importante em C ++ é usar tipos corretos. Portanto, a resposta correta para o seu problema (que inclui a resposta à pergunta que você fez) é a seguinte:

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

Isso sempre conterá a quantidade exata de bits que você precisa. Constrói a std::bitsetcom todos os bits definidos como 1 pelos mesmos motivos mencionados em outras respostas.

David Stone
fonte
0

É certamente seguro, pois -1 sempre terá todos os bits disponíveis definidos, mas eu gosto de ~ 0 melhor. -1 simplesmente não faz muito sentido para um unsigned int. 0xFF... não é bom porque depende da largura do tipo.

Zifre
fonte
4
"0xFF ... não é bom porque depende da largura do tipo" Qual é o único caminho sensato a percorrer, eu acho. Você deve definir claramente o que cada sinalizador / bit significa em seu programa. Então, se você definir que você está usando os menores de 32 bits para armazenar bandeiras, você deve restringir-se a usar esses 32 bits, se o tamanho real do int é 32 ou 64.
Juan Pablo Califano
0

Eu digo:

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

Isso sempre lhe dará o resultado desejado.

Alex
fonte
4
Não em sistemas com caracteres de 9 bits!
tc.
0

Aproveitar o fato de atribuir todos os bits a um para um tipo não assinado é equivalente a pegar o valor máximo possível para o tipo fornecido
e estender o escopo da pergunta a todos os tipos inteiros não assinados :

A atribuição de -1 funciona para qualquer tipo de número inteiro não assinado (int não assinado, uint8_t, uint16_t etc.) para C e C ++.

Como alternativa, para C ++, você pode:

  1. Incluir <limits>e usarstd::numeric_limits< your_type >::max()
  2. Escreva uma função de modelo personalizado (isso também permitiria alguma verificação de integridade, por exemplo, se o tipo de destino for realmente um tipo não assinado)

O objetivo poderia ser adicionar mais clareza, pois a atribuição -1sempre precisaria de alguns comentários explicativos.

Antonio
fonte
0

Uma maneira de tornar o significado um pouco mais óbvio e evitar repetir o tipo:

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

sim, a representação mostrada é muito correta, como se o fizéssemos o contrário, exigindo que um operador inverta todos os bits, mas, neste caso, a lógica é bastante direta se considerarmos o tamanho dos números inteiros na máquina

por exemplo, na maioria das máquinas, um número inteiro é 2 bytes = 16 bits, o valor máximo que pode armazenar é 2 ^ 16-1 = 65535 2 ^ 16 = 65536

0% 65536 = 0 -1% 65536 = 65535 que corresponde a 1111 ............. 1 e todos os bits são definidos como 1 (se considerarmos as classes de resíduos mod 65536), portanto, é muito direto.

eu acho

não, se você considerar essa noção, ela é perfeita para entradas não assinadas e funciona

basta verificar o seguinte 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;

}

resposta para b = 4294967295 que é -1% 2 ^ 32 em números inteiros de 4 bytes

portanto, é perfeitamente válido para números inteiros não assinados

em caso de qualquer discrepância plzz report

ankit sablok
fonte
9
Dois comentários: primeiro, você está completamente errado sobre o tamanho dos números inteiros na maioria das máquinas. Em segundo lugar, seu texto é muito difícil de ser lido 2, devido a um tipo de linguagem seckrit. Plz nos inglês simples .
Konrad Rudolph