Pergunta

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

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

Esta é uma boa maneira portátil para alcançar este objetivo? Ou está usando 0xffffffff ou ~0 melhor?

Foi útil?

Solução

Eu recomendo que você fazê-lo exatamente como você mostrou, uma vez que é o mais para a frente. Inicializar a -1 que irá funcionar sempre , independente da representação sinal real, enquanto ~, por vezes, têm um comportamento surpreendente, porque você terá que ter o tipo operando direito. Só então você vai ter o alto valor mais de um tipo de unsigned.

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

unsigned long a = ~0u;

Não vai necessariamente armazenar um padrão com todos os bits 1 em a. Mas vai primeiro criar um padrão com todos os bits 1 em um unsigned int e, em seguida, atribuí-la a a. O que acontece quando unsigned long tem mais bits é que nem todos os que são 1.

E considere este, que irá falhar em uma representação complemento não-dois de:

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

A razão para isso é que ~0 tem de inverter todos os bits. Invertendo que vai render -1 na máquina de complemento de dois (que é o valor que precisamos!), Mas irá não -1 rendimento em outra representação. Na máquina complemento de um um, ele produz zero. Assim, na máquina de complemento de um um, o acima irá inicializar a a zero.

A coisa que você deve entender é que é tudo sobre valores - não bits. A variável é inicializada com um valor . Se no initializer você modificar os bits da variável utilizada para a inicialização, o valor será gerado de acordo com esses bits. O valor que você precisa, para inicializar a para o valor mais alto possível, é -1 ou UINT_MAX. O segundo vai depender do tipo de a - você vai precisar usar ULONG_MAX para um unsigned long. No entanto, o primeiro não vai depender de seu tipo, e é uma boa maneira de obter o mais alto valor.

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

Mas o que estamos falando é que o resultado da variável flags inicializado é. E para isso, única -1 irá trabalhar com todos os tipos e máquina.

Outras dicas

  • unsigned int flags = -1; é portátil.
  • unsigned int flags = ~0; não é portátil porque depende de uma representação complemento de dois.
  • unsigned int flags = 0xffffffff; não é porque portátil ele assume ints de 32 bits.

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

Sinceramente eu acho que todos do fff é mais legível. Quanto ao comentário de que seu um antipattern, se você realmente se importa que todos os bits são definidos / apuradas, eu diria que você provavelmente está em uma situação onde você se preocupa com o tamanho da variável de qualquer maneira, o que exigiria algo como boost :: uint16_t, etc.

Uma maneira que evita os problemas mencionados é simplesmente fazer:

unsigned int flags = 0;
flags = ~flags;

portátil e direto ao ponto.

Eu não estou certo de usar um int não assinado para bandeiras é uma boa idéia em primeiro lugar em C ++. E sobre bitset e similares?

std::numeric_limit<unsigned int>::max() é melhor porque 0xffffffff assume que unsigned int é um número inteiro de 32-bit.

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

"Esta é uma boa [,] maneira portátil para fazer isso?"

Portable? Sim .

bom? Debatable , como evidenciado por toda a confusão exibidas nesta rosca. Sendo o suficiente claro que seus colegas programadores possam entender o código sem confusão deve ser uma das dimensões que medem de bom código.

Além disso, este método é propenso a compilador avisos . Elidir a advertência sem enfraquecer 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 requer que você preste atenção ao tipo de destino. Se você está prestando atenção ao tipo de alvo, então naturalmente você vai evitar as armadilhas de outras abordagens.

O meu conselho seria o de prestar atenção ao tipo de destino e certifique-se não existem 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 que são correta e mais óbvia aos seus colegas programadores.

E com C ++ 11 : Podemos usar auto para fazer qualquer um destes 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);

Eu considero correta e óbvia melhor do que simplesmente correto.

A conversão de -1 em qualquer tipo não assinado é garantida pelo padrão para resultar em todos os-queridos. Uso de ~0U geralmente é ruim, já que 0 tem o tipo unsigned int e não irá preencher todos os bits de um tipo não assinado maior, a menos que algo explicitamente escrita como ~0ULL. Em sistemas sãos, ~0 deve ser idêntico ao -1, mas desde que a norma permite complemento queridos-e sinal / representações magnitude, estritamente falando, não é portátil.

É claro que é sempre bom para escrever 0xffffffff se você sabe o que você precisa exatamente 32 bits, mas -1 tem a vantagem de que ele vai trabalhar em qualquer contexto, mesmo quando você não sabe o tamanho do tipo, como macros que trabalho em vários tipos, ou se o tamanho do tipo varia de acordo com a implementação. Se você não sabe o tipo, outra forma segura de obter todos os-ones é o macros limite UINT_MAX, ULONG_MAX, ULLONG_MAX, etc.

Pessoalmente eu uso sempre -1. Ele sempre funciona e você não tem que pensar sobre isso.

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

Para resolver estes problemas, tente este helper simples:

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;

Enquanto você tem #include <limits.h> como um de seus inclui, você deve apenas usar

unsigned int flags = UINT_MAX;

Se você quiser o valor de um longa de bits, você pode usar

unsigned long flags = ULONG_MAX;

Estes valores são a garantia de ter todos os bits do valor do conjunto de resultados a 1, independentemente de como inteiros assinados são implementadas.

Eu não faria a -1 coisa. É um pouco não-intuitivo (pelo menos para mim). Atribuindo dados assinados a uma variável unsigned 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, eu muito raramente ver a -1 truque feito em 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 o uint8_t de largura fixa, uint16_t, tipos uint32_t.

processadores em Intel IA-32 é OK para escrever 0xFFFFFFFF para um registo de 64 bits e obter os resultados esperados. Isto é porque IA32E (a extensão de 64 bits para IA32) suporta apenas imediatos de 32 bits. Em instruções de 64 bits imediatos de 32 bits são estendeu-sinal para 64-bits.

A seguir é ilegal:

mov rax, 0ffffffffffffffffh

Os seguintes puts 64 1s em RAX:

mov rax, 0ffffffffh

Apenas para completar, os seguintes puts 32 1s na parte inferior da RAX (aka EAX):

mov eax, 0ffffffffh

E, na verdade eu tive programas falhar quando eu queria escrever 0xffffffff a uma variável de 64 bits e eu tenho um 0xffffffffffffffff vez. Em C este seria:

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

O resultado é:

x is 0xffffffffffffffff

Eu pensei para postar isso como um comentário a todas as respostas que diziam que 0xFFFFFFFF assume 32 bits, mas muitas pessoas respondeu que eu percebi que eu adicioná-lo como uma resposta em separado.

resposta See de litb para uma explicação muito clara das questões.

Meu desacordo é que, muito estritamente falando, não há garantias para ambos os casos. Eu não sei de qualquer arquitetura que não representa um valor sem sinal de 'um a menos que dois à potência do número de bits' como todos os bits definidos, mas aqui é o que o padrão realmente diz (3.9.1 / 7 mais nota 44):

As representações dos tipos integrais deve definir valores pelo uso de um sistema de numeração binário puro. [Nota 44:] Uma representação posicional para inteiros que utiliza os elementos binários 0 e 1, em que os valores representados por bits sucessivos são aditivos, começar com um, e são multiplicados por sucessiva poder integrante de 2, excepto, talvez, para o bit com a posição mais alta.

Isso deixa a possibilidade de um dos bits a ser nada.

Praticamente: Sim

Teoricamente:. Não

-1 = 0xFFFFFFFF (ou o tamanho de um int está em sua plataforma) só é verdade com dois complemento da aritmética. Na prática, ele vai trabalhar, mas existem máquinas de legado lá fora (mainframes da IBM, etc.), onde você tem um bit de sinal real em vez de representação, uma de complemento de dois. Seu ~ 0 solução proposta deve funcionar em todos os lugares.

Embora o 0xFFFF (ou 0xFFFFFFFF, etc.) pode ser mais fácil de ler, pode quebrar a portabilidade em 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 tem determinado conjunto pedaços (bits exatas sendo especificado pelo chamador). A rotina pode ser totalmente agnóstico quanto ao que os bits representam, mas ainda precisa ter uma "todos os bits set" constante. Em tal caso, um, -1 será muito melhor do que uma constante hexadecimal uma vez que irá trabalhar com qualquer tamanho de bit.

A outra possibilidade, se um valor typedef é usado para a máscara de bits, seria usar ~ (bitMaskType) 0; se bitmask passa a ser apenas um tipo de 16 bits, essa expressão só terá 16 bits definido (mesmo que 'int' de outra forma seria 32 bits), mas desde 16 bits vai ser tudo o que são necessários, as coisas devem ficar bem fornecido que se usa realmente o tipo apropriado na typecast.

Aliás, expressões do longvar &= ~[hex_constant] forma tem uma pegadinha desagradável se a constante hexadecimal é muito grande para caber em uma int, mas vai caber em uma unsigned int. Se um int é de 16 bits, então longvar &= ~0x4000; ou longvar &= ~0x10000; irá limpar um pouco de longvar, mas longvar &= ~0x8000; irá limpar bit bits 15 e todos os acima disso. Valores que se encaixam em int terá o operador complemento aplicado a um tipo int, mas o resultado será sinal estendido para long, definindo os bits superiores. Valores que são grandes demais para unsigned int terá o operador complemento aplicado para digitar long. Valores que estão entre os tamanhos, no entanto, será aplicado o operador complemento tipo unsigned int, que depois serão convertidos para o tipo long sem extensão de sinal.

Como já foi mencionado, -1 é a maneira correta de criar um inteiro que irá converter para um tipo não assinado com todos os bits definidos como 1. No entanto, a coisa mais importante em C ++ está usando tipos corretos. Portanto, a resposta correta para o seu problema (que inclui a resposta para a pergunta que você fez) é a seguinte:

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

Esta será sempre contêm a quantidade exata de bits que você precisa. Ele constrói um std::bitset com todos os bits definidos como 1, pelas mesmas razões mencionadas em outras respostas.

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

Eu digo:

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

Este sempre lhe dará o resultado desejado.

Aproveitando o fato de que a atribuição de todos os bits de um para um tipo não assinado é equivalente a tirar o máximo valor possível para o tipo de dado,
e alargar o âmbito da questão a todos sem assinatura tipos inteiros:

Atribuindo -1 funciona para qualquer sem assinatura tipo inteiro (unsigned int, uint8_t, uint16_t , etc.) para C e C ++.

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

  1. Incluir <limits> e uso std::numeric_limits< your_type >::max()
  2. Escreva uma função templated costume (Isso também permitiria que alguma verificação de sanidade, ou seja, se o tipo de destino é realmente um sem assinatura digite)

O objetivo poderia ser adicionar mais clareza, como a atribuição de -1 sempre precisa de algum comentário explicativo.

Uma maneira de fazer o significado pouco mais óbvio e ainda para evitar a repetição do tipo:

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

sim a representação apresentada é muito correto como se o fizermos o contrário u vai exigir um operador para reverter todos os bits, mas, neste caso, a lógica é bastante simples, se considerarmos o tamanho dos inteiros na máquina

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

0% 65536 = 0 -1% 65536 = 65535 que corressponds a 1111 ............. 1 e todos os bits são definidos para um (se consideram as classes de resíduos mod 65536) portanto, é muito simples.

Eu acho

Não se u considerar esta noção é jantar perfeitamente para ints não assinados e ele realmente funciona

Apenas verifique 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 nar é -1% 2 ^ 32 em números inteiros 4 bytes

Por isso, é perfeitamente válida para inteiros sem sinal

em caso de relatório quaisquer discrepâncias Plzz

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top