Use o operador OR bit a bit ( |) para definir um pouco.
number |=1UL<< n;
Isso definirá o nth bit de number. ndeve ser zero, se você deseja definir o 1st bit e assim por diante n-1, se deseja definir o nth bit.
Use 1ULLse numberfor maior que unsigned long; a promoção de 1UL << nnão acontece até depois de avaliar 1UL << nonde o comportamento indefinido muda mais do que a largura de umlong . O mesmo se aplica a todo o restante dos exemplos.
Limpando um pouco
Use o operador AND bit a bit ( &) para limpar um pouco.
number &=~(1UL<< n);
Isso limpará o nth th de number. Você deve inverter a string de bits com o operador NOT bit a bit (~ ) e depois AND.
Alternando um pouco
O operador XOR ( ^) pode ser usado para alternar um pouco.
number ^=1UL<< n;
Isso alternará o nth bit denumber .
Verificando um pouco
Você não pediu isso, mas eu poderia adicioná-lo.
Para verificar um pouco, desloque o número n para a direita e, em seguida, bit a bit E:
bit =(number >> n)&1U;
Isso colocará o valor do nth bit numberna variávelbit .
Alterando o n ésimo bit para x
Definir o nth bit como um 1ou 0pode ser alcançado com o seguinte na implementação C ++ de um complemento de 2:
number ^=(-x ^ number)&(1UL<< n);
O bit nserá definido se xestiver 1e limpo se xestiver 0. Se xtiver algum outro valor, você recebe lixo. x = !!xo booleanizará para 0 ou 1.
Para tornar isso independente do comportamento de negação do complemento de 2 (onde -1todos os bits foram definidos, diferentemente do complemento de 1 ou da implementação de sinal / magnitude C ++), use negação não assinada.
number ^=(-(unsignedlong)x ^ number)&(1UL<< n);
ou
unsignedlong newbit =!!x;// Also booleanize to force 0 or 1
number ^=(-newbit ^ number)&(1UL<< n);
Geralmente, é uma boa ideia usar tipos não assinados para manipulação portátil de bits.
ou
number =(number &~(1UL<< n))|(x << n);
(number & ~(1UL << n))irá limpar o nth bit e (x << n)definirá o nth bit parax .
Também é geralmente uma boa idéia não copiar / colar código em geral e muitas pessoas usam macros de pré-processador (como a resposta do wiki da comunidade mais adiante ) ou algum tipo de encapsulamento.
Eu gostaria de observar que, em plataformas que têm suporte nativo para bit set / clear (por exemplo, microcontroladores AVR), os compiladores geralmente traduzem 'myByte | = (1 << x)' nas instruções nativas de set / clear sempre que x é uma constante, ex: (1 << 5), ou const unsigned x = 5.
Aaron
52
bit = número & (1 << x); não colocará o valor do bit x no bit, a menos que o bit tenha o tipo _Bool (<stdbool.h>). Caso contrário, bit = !! (número & (1 << x)); vai ..
Chris Young
23
por que você não muda o último parabit = (number >> x) & 1
aaronman 26/06
42
1é um intliteral, que é assinado. Portanto, todas as operações aqui operam com números assinados, o que não é bem definido pelos padrões. Os padrões não garantem o complemento de dois ou a mudança aritmética, portanto é melhor usá-lo 1U.
Siyuan Ren
50
Prefiro number = number & ~(1 << n) | (x << n);Alterar o n-ésimo bit para x.
A versão Boost permite um conjunto de bits do tamanho de tempo de execução em comparação com um conjunto de bits do tamanho de compilação da biblioteca padrão .
+1. Não que std :: bitset seja utilizável em "C", mas como o autor marcou sua pergunta com "C ++", AFAIK, sua resposta é a melhor por aqui ... std :: vector <bool> é outra maneira, se alguém conhece seus prós e seus contras
paercebal
23
@andrewdotnich: o vetor <bool> é (infelizmente) uma especialização que armazena os valores como bits. Veja gotw.ca/publications/mill09.htm para obter mais informações ...
Niklas
71
Talvez ninguém tenha mencionado isso porque isso foi marcado como incorporado. Na maioria dos sistemas embarcados, você evita o STL como uma praga. E o suporte ao impulso é provavelmente um pássaro muito raro para ser encontrado entre a maioria dos compiladores incorporados.
Lundin
17
@ Martin É muito verdade. Além de matadores de desempenho específicos, como STL e modelos, muitos sistemas embarcados até evitam completamente todas as bibliotecas padrão, porque são difíceis de verificar. A maior parte da filial incorporada está adotando padrões como o MISRA, que requer ferramentas de análise de código estáticas (qualquer profissional de software deve estar usando essas ferramentas, não apenas as pessoas incorporadas). Geralmente, as pessoas têm coisas melhores a fazer do que executar análises estáticas em toda a biblioteca padrão - se o código-fonte estiver disponível para elas no compilador específico.
Lundin
37
@Lundin: Suas declarações são excessivamente amplas (portanto, inútil discutir sobre isso). Estou certo de que posso encontrar situações em que são verdadeiras. Isso não muda meu ponto inicial. Ambas as classes são perfeitamente adequadas para uso em sistemas embarcados (e eu sei que elas são usadas). Seu ponto inicial sobre o STL / Boost não ser usado em sistemas embarcados também está errado. Tenho certeza de que existem sistemas que não os utilizam e mesmo os sistemas que os utilizam são usados criteriosamente, mas dizer que não são usados não é correto (porque existem sistemas em que são usados).
define um campo de 3 bits (na verdade, são três campos de 1 bit). As operações de bit agora se tornam um pouco (haha) mais simples:
Para definir ou limpar um pouco:
mybits.b =1;
mybits.c =0;
Para alternar um pouco:
mybits.a =!mybits.a;
mybits.b =~mybits.b;
mybits.c ^=1;/* all work */
Verificando um pouco:
if(mybits.c)//if mybits.c is non zero the next line below will execute
Isso funciona apenas com campos de bits de tamanho fixo. Caso contrário, você precisará recorrer às técnicas de manipulação de bits descritas nas postagens anteriores.
Sempre achei que usar campos de bits é uma má ideia. Você não tem controle sobre a ordem em que os bits são alocados (de cima ou de baixo), o que torna impossível serializar o valor de maneira estável / portátil, exceto bit por vez. Também é impossível misturar aritmética de bits DIY com campos de bits, por exemplo, criando uma máscara que testa vários bits ao mesmo tempo. Obviamente, você pode usar o && e esperar que o compilador o otimize corretamente ...
R .. GitHub PARE DE AJUDAR O GELO
34
Os campos de bits são ruins de muitas maneiras, eu quase poderia escrever um livro sobre isso. Na verdade, eu quase tive que fazer isso em um programa de campo que precisava de conformidade com MISRA-C. O MISRA-C impõe que todo comportamento definido pela implementação seja documentado, então acabei escrevendo um ensaio sobre tudo o que pode dar errado nos campos de bits. Ordem de bits, endianess, bits de preenchimento, bytes de preenchimento, vários outros problemas de alinhamento, conversões de tipo implícitas e explícitas de e para um campo de bits, UB se int não for usado e assim por diante. Em vez disso, use operadores bit a bit para menos erros e código portátil. Os campos de bits são completamente redundantes.
Lundin
44
Como a maioria dos recursos de idioma, os campos de bits podem ser usados corretamente ou podem ser abusados. Se você precisar compactar vários valores pequenos em um único int, os campos de bits podem ser muito úteis. Por outro lado, se você começar a fazer suposições sobre como os campos de bit são mapeados para o int que contém, você está apenas pedindo problemas.
Ferruccio
4
@ endolith: Isso não seria uma boa ideia. Você poderia fazê-lo funcionar, mas não seria necessariamente portátil para um processador diferente, ou para um compilador diferente, ou mesmo para a próxima versão do mesmo compilador.
Ferruccio
3
@Yasky e Ferruccio, obtendo respostas diferentes para sizeof () para essa abordagem, devem ilustrar os problemas de compatibilidade não apenas entre os compiladores, mas também no hardware. Às vezes nos enganamos que resolvemos esses problemas com idiomas ou tempos de execução definidos, mas na verdade se resume a 'funcionará na minha máquina?'. Vocês incorporados têm o meu respeito (e simpatias).
Kelly S. French
181
Eu uso macros definidas em um arquivo de cabeçalho para manipular o conjunto de bits e limpar:
/* a=target variable, b=bit number to act upon 0-n */#define BIT_SET(a,b)((a)|=(1ULL<<(b)))#define BIT_CLEAR(a,b)((a)&=~(1ULL<<(b)))#define BIT_FLIP(a,b)((a)^=(1ULL<<(b)))#define BIT_CHECK(a,b)(!!((a)&(1ULL<<(b))))// '!!' to make sure this returns 0 or 1/* x=target variable, y=mask */#define BITMASK_SET(x,y)((x)|=(y))#define BITMASK_CLEAR(x,y)((x)&=(~(y)))#define BITMASK_FLIP(x,y)((x)^=(y))#define BITMASK_CHECK_ALL(x,y)(((x)&(y))==(y))// warning: evaluates y twice#define BITMASK_CHECK_ANY(x,y)((x)&(y))
Uh Sei que este é um post 5 anos de idade, mas não haja duplicação argumento em qualquer uma dessas macros, Dan
Robert Kelly
11
BITMASK_CHECK(x,y) ((x) & (y))deve ser ((x) & (y)) == (y)de outra forma retorna resultado incorreto na máscara multibit (ex. 5vs. 3/ * Olá a todos os coveiros:) * /)
Brigadir
7
1deve ser (uintmax_t)1ou semelhantes no caso de alguém tentar usar essas macros em um longou tipo maior
MM
2
BITMASK_CHECK_ALL(x,y)pode ser implementado como #!~((~(y))|(x))
Handy999 /
3
@ Handy999 É um pouco mais fácil de ver por que as obras após a aplicação da lei e de De Morgan re-organizar para chegar!(~(x) & (y))
Tavian Barnes
114
Às vezes vale a pena usar um enumpara nomear os bits:
Como alternativa, você pode fazer uma clearbits()função em vez de &= ~. Por que você está usando um enum para isso? Eu pensei que eram para criar um monte de variáveis únicas com valor arbitrário oculto, mas você está atribuindo um valor definido para cada uma. Então, qual é o benefício versus apenas defini-los como variáveis?
endolith
4
@ endolith: O uso de enums para conjuntos de constantes relacionadas remonta a um longo caminho na programação c. Eu suspeito que, com os compiladores modernos, a única vantagem sobre const shortou o que quer que seja é que eles estão explicitamente agrupados. E quando você quer que eles para algo outro do que bitmasks você começa a numeração automática. No c ++, é claro, eles também formam tipos distintos, o que fornece uma verificação extra de erros estáticos.
dmckee --- gatinho ex-moderador
Você entrará em constantes enum indefinidas se não definir uma constante para cada um dos valores possíveis dos bits. Qual é o enum ThingFlagsvalor ThingError|ThingFlag1, por exemplo?
Luis Colorado
6
Se você usar esse método, lembre-se de que as constantes enum são sempre do tipo assinado int. Isso pode causar todos os tipos de erros sutis devido à promoção de número inteiro implícito ou operações bit a bit em tipos assinados. thingstate = ThingFlag1 >> 1por exemplo, chamará o comportamento definido pela implementação. thingstate = (ThingFlag1 >> x) << ypode invocar um comportamento indefinido. E assim por diante. Para estar seguro, sempre faça a conversão para um tipo não assinado.
Lundin
1
@Lundin: A partir do C ++ 11, você pode definir o tipo subjacente de uma enumeração, por exemplo: enum My16Bits: unsigned short { ... };
/*
** Bit set, clear, and test operations
**
** public domain snippet by Bob Stout
*/typedefenum{ERROR =-1, FALSE, TRUE} LOGICAL;#define BOOL(x)(!(!(x)))#defineBitSet(arg,posn)((arg)|(1L<<(posn)))#defineBitClr(arg,posn)((arg)&~(1L<<(posn)))#defineBitTst(arg,posn) BOOL((arg)&(1L<<(posn)))#defineBitFlp(arg,posn)((arg)^(1L<<(posn)))
OK, vamos analisar as coisas ...
A expressão comum com a qual você parece estar tendo problemas em tudo isso é "(1L << (posn))". Tudo isso é criar uma máscara com um único bit ativado e que funcionará com qualquer tipo de número inteiro. O argumento "posn" especifica a posição em que você deseja o bit. Se posn == 0, esta expressão será avaliada para:
00000000000000000000000000000001 binary.
Se posn == 8, ele avaliará como:
00000000000000000000000100000000 binary.
Em outras palavras, ele simplesmente cria um campo de 0 com um 1 na posição especificada. A única parte complicada está na macro BitClr (), na qual precisamos definir um único 0 bit em um campo de 1's. Isso é feito usando o complemento 1 da mesma expressão, conforme indicado pelo operador til (~).
Depois que a máscara é criada, ela é aplicada ao argumento, como você sugere, usando os operadores bit a bit e (&), ou (|) e xor (^). Como a máscara é do tipo longa, as macros também funcionarão com caracteres char, short, int ou long.
A linha inferior é que esta é uma solução geral para toda uma classe de problemas. É claro que é possível e até apropriado reescrever o equivalente a qualquer uma dessas macros com valores explícitos de máscara toda vez que você precisar, mas por que fazer isso? Lembre-se de que a substituição da macro ocorre no pré-processador e, portanto, o código gerado refletirá o fato de que os valores são considerados constantes pelo compilador - ou seja, é tão eficiente usar as macros generalizadas quanto "reinventar a roda" toda vez que você precisar faça manipulação de bits.
Não convencido? Aqui está um código de teste - usei o Watcom C com otimização total e sem usar _cdecl para que a desmontagem resultante fosse a mais limpa possível:
#define BOOL(x)(!(!(x)))#defineBitSet(arg,posn)((arg)|(1L<<(posn)))#defineBitClr(arg,posn)((arg)&~(1L<<(posn)))#defineBitTst(arg,posn) BOOL((arg)&(1L<<(posn)))#defineBitFlp(arg,posn)((arg)^(1L<<(posn)))int bitmanip(int word){
word =BitSet(word,2);
word =BitSet(word,7);
word =BitClr(word,3);
word =BitFlp(word,9);return word;}
2 coisas sobre isso: (1) ao examinar suas macros, alguns podem acreditar incorretamente que as macros realmente configuram / limpam / invertem bits no argumento, no entanto, não há atribuição; (2) seu test.c não está completo; Eu suspeito que se você executou mais casos você gostaria de encontrar um (exercício leitor) problema
Dan
19
-1 Isso é apenas uma ofuscação estranha. Nunca reinvente a linguagem C ocultando a sintaxe da linguagem atrás das macros, é uma prática muito ruim. Depois, algumas curiosidades: primeiro, 1L é assinado, o que significa que todas as operações de bit serão executadas em um tipo assinado. Tudo o que é passado para essas macros retornará como assinado por muito tempo. Não é bom. Segundo, isso funcionará de maneira muito ineficiente em CPUs menores, uma vez que impõe muito tempo quando as operações podem estar no nível int. Terceiro, as macros funcionais são a raiz de todo mal: você não tem nenhum tipo de segurança. Além disso, o comentário anterior sobre nenhuma atribuição é muito válido.
Lundin
2
Isso irá falhar se argfor long long. 1Lprecisa ser o tipo mais amplo possível (uintmax_t)1. (Você pode se safar 1ull)
MM
Você otimizou para o tamanho do código? Nas CPUs mainstream da Intel, você obtém paradas parciais de registro ao ler AX ou EAX após o retorno dessa função, porque ela grava os componentes de 8 bits do EAX. (É bom para as CPUs AMD ou outras que não renomeiam registros parciais separadamente do registro completo. Haswell / Skylake não renomeia AL separadamente, mas renomeiam AH. ).
Peter Cordes
37
Use os operadores bit a bit: &|
Para definir o último bit em 000b:
foo = foo |001b
Para verificar o último bit foo:
if( foo &001b)....
Para limpar o último bit em foo:
foo = foo &110b
Eu costumava ter XXXbclareza. Você provavelmente estará trabalhando com representação HEX, dependendo da estrutura de dados na qual está compactando bits.
Aqui está minha macro aritmética de bits favorita, que funciona para qualquer tipo de matriz inteira não assinada de unsigned charaté size_t(que é o maior tipo que deve ser eficiente para trabalhar):
#define BITOP(a,b,op) \
((a)[(size_t)(b)/(8*sizeof*(a))] op ((size_t)1<<((size_t)(b)%(8*sizeof*(a)))))
É bom ler, mas é preciso estar ciente dos possíveis efeitos colaterais. O uso BITOP(array, bit++, |=);em loop provavelmente não fará o que o chamador deseja.
13/07
De fato. =) Uma variante que você pode preferir é separá-lo em 2 macros, 1 para endereçar o elemento da matriz e a outra para colocar o bit no lugar, ala BITCELL(a,b) |= BITMASK(a,b);(ambos usam acomo argumento para determinar o tamanho, mas o último nunca avaliaria adesde aparece apenas em sizeof).
R .. GitHub Pare de ajudar o gelo
1
@R .. Esta resposta é muito antiga, mas eu provavelmente preferiria uma função a uma macro neste caso.
PC Luddite
Menor: a 3ª (size_t)elenco parecem estar lá apenas para segurar alguns matemática não assinado com %. Poderia (unsigned)lá.
chux - Restabelece Monica
O (size_t)(b)/(8*sizeof *(a))desnecessariamente poderia diminuir bantes da divisão. Apenas um problema com matrizes de bits muito grandes. Ainda uma macro interessante.
chux - Restabelece Monica
25
Como isso está marcado como "incorporado", assumirei que você está usando um microcontrolador. Todas as sugestões acima são válidas e funcionam (leitura-modificação-gravação, uniões, estruturas, etc.).
No entanto, durante um período de depuração baseada em osciloscópio, fiquei surpreso ao descobrir que esses métodos têm uma sobrecarga considerável nos ciclos da CPU em comparação com a gravação de um valor diretamente nos registros PORTnSET / PORTnCLEAR do micro, o que faz uma diferença real quando existem loops estreitos / altos pinos de alternância do ISR de alta frequência.
Para quem não conhece: No meu exemplo, o micro possui um registro geral de estado de pino PORTn, que reflete os pinos de saída, e PORTn | = BIT_TO_SET resulta em uma leitura-modificação-gravação no registro. No entanto, os registradores PORTnSET / PORTnCLEAR levam um '1' para significar "por favor, faça este bit 1" (SET) ou "por favor, faça este bit zero" (CLEAR) e um '0' para significar "deixe o pino em paz". portanto, você acaba com dois endereços de porta, dependendo de definir ou limpar o bit (nem sempre é conveniente), mas uma reação muito mais rápida e um código montado menor.
Micro era o Coldfire MCF52259, usando C no Codewarrior. Olhar para o desmontador / asm é um exercício útil, pois mostra todas as etapas pelas quais a CPU precisa executar para realizar a operação mais básica. Também vimos outras instruções de sobrecarga da CPU em loops críticos para o tempo - restringir uma variável fazendo var% = max_val custa uma pilha de ciclos de CPU toda vez, enquanto fazemos se (var> max_val) var- = max_val usa apenas algumas instruções. <br> Um bom guia para mais alguns truques está aqui: codeproject.com/Articles/6154/…
John U
Ainda mais importante, os registros de E / S mapeados na memória auxiliar fornecem um mecanismo para atualizações atômicas. A leitura / modificação / gravação pode ser muito ruim se a sequência for interrompida.
Ben Voigt
1
Lembre-se de que todos os registros de porta serão definidos como volatilee, portanto, o compilador não pode executar nenhuma otimização no código que envolve esses registros. Portanto, é uma boa prática desmontar esse código e ver como ficou no nível do assembler.
Lundin
24
A abordagem de campo de bits tem outras vantagens na arena incorporada. Você pode definir uma estrutura que mapeie diretamente os bits em um registro de hardware específico.
structHwRegister{unsignedint errorFlag:1;// one-bit flag fieldunsignedintMode:3;// three-bit mode fieldunsignedintStatusCode:4;// four-bit status code};structHwRegister CR3342_AReg;
Você precisa estar ciente da ordem de compactação de bits - acho que é o MSB primeiro, mas isso pode depender da implementação. Além disso, verifique como os campos de manipuladores do compilador cruzam os limites de bytes.
Você pode então ler, escrever, testar os valores individuais como antes.
Praticamente tudo sobre os campos de bits é definido pela implementação. Mesmo que você consiga descobrir todos os detalhes sobre como seu compilador os implementa, usá-los em seu código certamente o tornará não portátil.
Lundin
1
@Lundin - É verdade, mas o sistema embarcado é complicado (principalmente nos registros de hardware, que é a minha resposta) nunca será útil de qualquer maneira.
Roddy
1
Talvez não entre CPUs totalmente diferentes. Mas você provavelmente deseja que seja portátil entre compiladores e entre projetos diferentes. E há muitas "quebra de bits" incorporadas que não estão relacionadas ao hardware, como codificação / decodificação de protocolo de dados.
Lundin
... e se você tem o hábito de usar campos de bits na programação incorporada, verá que seu código X86 é mais rápido e mais enxuto. Não em benchmarks simples, onde você tem toda a máquina para esmagar o benchmark, mas em ambientes multitarefa do mundo real, onde os programas competem por recursos. Vantagem CISC - cujo objetivo original era compensar as CPUs mais rapidamente do que os barramentos e diminuir a memória.
20
Verifique um pouco em um local arbitrário em uma variável do tipo arbitrário:
int main(void){unsignedchar arr[8]={0x01,0x23,0x45,0x67,0x89,0xAB,0xCD,0xEF};for(int ix =0; ix <64;++ix)
printf("bit %d is %d\n", ix, bit_test(arr, ix));return0;}
Notas:
Ele foi projetado para ser rápido (dada sua flexibilidade) e não ramificado. Isso resulta em um código de máquina SPARC eficiente quando compilado o Sun Studio 8; Também testei usando o MSVC ++ 2008 em amd64. É possível criar macros semelhantes para definir e limpar bits. A principal diferença desta solução em comparação com muitas outras aqui é que ela funciona para qualquer local em praticamente qualquer tipo de variável.
Se você está mexendo bastante, talvez queira usar máscaras, o que tornará tudo mais rápido. As funções a seguir são muito rápidas e ainda são flexíveis (elas permitem rodar bit em bit maps de qualquer tamanho).
constunsignedcharTQuickByteMask[8]={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80,};/** Set bit in any sized bit mask.
*
* @return none
*
* @param bit - Bit number.
* @param bitmap - Pointer to bitmap.
*/voidTSetBit(short bit,unsignedchar*bitmap){short n, x;
x = bit /8;// Index to byte.
n = bit %8;// Specific bit in byte.
bitmap[x]|=TQuickByteMask[n];// Set bit.}/** Reset bit in any sized mask.
*
* @return None
*
* @param bit - Bit number.
* @param bitmap - Pointer to bitmap.
*/voidTResetBit(short bit,unsignedchar*bitmap){short n, x;
x = bit /8;// Index to byte.
n = bit %8;// Specific bit in byte.
bitmap[x]&=(~TQuickByteMask[n]);// Reset bit.}/** Toggle bit in any sized bit mask.
*
* @return none
*
* @param bit - Bit number.
* @param bitmap - Pointer to bitmap.
*/voidTToggleBit(short bit,unsignedchar*bitmap){short n, x;
x = bit /8;// Index to byte.
n = bit %8;// Specific bit in byte.
bitmap[x]^=TQuickByteMask[n];// Toggle bit.}/** Checks specified bit.
*
* @return 1 if bit set else 0.
*
* @param bit - Bit number.
* @param bitmap - Pointer to bitmap.
*/shortTIsBitSet(short bit,constunsignedchar*bitmap){short n, x;
x = bit /8;// Index to byte.
n = bit %8;// Specific bit in byte.// Test bit (logigal AND).if(bitmap[x]&TQuickByteMask[n])return1;return0;}/** Checks specified bit.
*
* @return 1 if bit reset else 0.
*
* @param bit - Bit number.
* @param bitmap - Pointer to bitmap.
*/shortTIsBitReset(short bit,constunsignedchar*bitmap){returnTIsBitSet(bit, bitmap)^1;}/** Count number of bits set in a bitmap.
*
* @return Number of bits set.
*
* @param bitmap - Pointer to bitmap.
* @param size - Bitmap size (in bits).
*
* @note Not very efficient in terms of execution speed. If you are doing
* some computationally intense stuff you may need a more complex
* implementation which would be faster (especially for big bitmaps).
* See (http://graphics.stanford.edu/~seander/bithacks.html).
*/intTCountBits(constunsignedchar*bitmap,int size){int i, count =0;for(i=0; i<size; i++)if(TIsBitSet(i, bitmap))
count++;return count;}
Observe que, para definir o bit 'n' em um número inteiro de 16 bits, faça o seguinte:
TSetBit( n,&my_int);
Cabe a você garantir que o número de bits esteja dentro do intervalo do mapa de bits que você passa. Observe que, para pequenos processadores endian, que bytes, palavras, dwords, qwords etc. são mapeados corretamente um para o outro na memória (principal motivo pelo qual os pequenos processadores endian são 'melhores' que os processadores big endian, ah, sinto uma guerra de chamas chegando em...).
Não use uma tabela para uma função que possa ser implementada com um único operador. TQuickByteMask [n] é equivalente a (1 << n). Além disso, encurtar seus argumentos é uma péssima idéia. O / e% serão na verdade uma divisão, não bits / shift / bit a bit e, porque a divisão assinada por uma potência de 2 não pode ser implementada bit a bit. Você deve deixar o tipo de argumento int sem assinatura!
R .. GitHub Pare de ajudar o gelo
Qual o sentido disso? Isso apenas torna o código mais lento e difícil de ler? Não vejo uma única vantagem nisso. 1u << n é mais fácil de ler para programadores C e, esperançosamente, pode ser traduzido em uma única instrução de CPU com tick de clock. Sua divisão, por outro lado, será traduzida para algo em torno de 10 ticks, ou mesmo até 100 ticks, dependendo de quão mal a arquitetura específica lida com a divisão. Quanto ao recurso de bitmap, faria mais sentido ter uma tabela de pesquisa traduzindo cada índice de bits em um índice de bytes, para otimizar a velocidade.
Lundin
2
Quanto ao big / little endian, o big endian mapeará números inteiros e dados brutos (por exemplo, seqüências de caracteres) da mesma maneira: da esquerda para a direita msb para lsb em todo o bitmap. Embora little endian mapeie números inteiros da esquerda para a direita como 7-0, 15-8, 23-18, 31-24, mas os dados brutos ainda são da esquerda para a direita msb para lsb. Então, quão pouco endian é melhor para o seu algoritmo em particular está completamente além de mim, parece ser o oposto.
Lundin
2
@R .. Uma tabela pode ser útil se o seu plattform não pode mudar de forma eficiente, como o velho microchip MCU, mas é claro que, em seguida, a divisão da amostra é absolutamente ineficiente
jeb
12
Usa isto:
intToggleNthBit(unsignedchar n,int num ){if(num &(1<< n))
num &=~(1<< n);else
num |=(1<< n);return num;}
set_bit Atomicallyset a bit in memory
clear_bit Clears a bit in memory
change_bit Toggle a bit in memory
test_and_set_bit Set a bit andreturn its old value
test_and_clear_bit Clear a bit andreturn its old value
test_and_change_bit Change a bit andreturn its old value
test_bit Determine whether a bit isset
Nota: Aqui toda a operação acontece em uma única etapa. Portanto, todos eles são garantidos como atômicos, mesmo em computadores SMP, e são úteis para manter a coerência entre os processadores.
O Visual C 2010, e talvez muitos outros compiladores, têm suporte direto para operações booleanas incorporadas. Um bit tem dois valores possíveis, assim como um booleano, para que possamos usar booleanos - mesmo que ocupem mais espaço do que um único bit. memória nesta representação. Isso funciona, até o sizeof()operador funciona corretamente.
Portanto, para sua pergunta, IsGph[i] =1ou IsGph[i] =0facilite a configuração e limpeza de bools.
Para encontrar caracteres não imprimíveis:
// Initialize boolean array to detect UN-printable characters, // then call function to toggle required bits true, while initializing a 2nd// boolean array as the complement of the 1st.for(i=0; i<sizeof(IsGph); i++){if(IsGph[i]){IsNotGph[i]=0;}else{IsNotGph[i]=1;}}
Observe que não há nada de "especial" nesse código. Trata-se um pouco como um número inteiro - o que tecnicamente é. Um número inteiro de 1 bit que pode conter 2 valores e apenas 2 valores.
Uma vez, usei essa abordagem para encontrar registros duplicados de empréstimos, em que loan_number era a chave ISAM, usando o número de empréstimo de 6 dígitos como índice na matriz de bits. Savagely rápido, e após 8 meses, provou que o sistema de mainframe do qual estávamos obtendo os dados estava de fato com defeito. A simplicidade das matrizes de bits torna a confiança em sua correção muito alta - em comparação com uma abordagem de pesquisa, por exemplo.
std :: bitset é de fato implementado como bits pela maioria dos compiladores
galinette
@ galinette, concordou. O arquivo de cabeçalho #include <bitset> é um bom recurso nesse sentido. Além disso, o vetor de classe especial <bool> para quando você precisar alterar o tamanho do vetor. O C ++ STL, segunda edição, Nicolai M. Josuttis, aborda-os exaustivamente nas páginas 650 e 281, respectivamente. O C ++ 11 adiciona alguns novos recursos ao std :: bitset, de interesse especial para mim é uma função hash em contêineres não-ordenados. Obrigado pela atenção! Vou excluir meu comentário de cãibra no cérebro. Já chega de lixo na web. Eu não quero adicionar a isso.
3
Isso usa pelo menos um byte inteiro de armazenamento para cada um bool. Talvez até 4 bytes para configurações C89 que usam intpara implementarbool
MM
@MattMcNabb, você está correto. Em C ++, o tamanho do tipo int necessário para implementar um booleano não é especificado pelo padrão. Percebi que essa resposta estava errada há algum tempo, mas decidi deixá-la aqui, pois as pessoas aparentemente a acham útil. Para aqueles que querem pedaços de uso comentário de galinette é mais útil como é minha biblioteca pouco aqui ... stackoverflow.com/a/16534995/1899861
2
@RocketRoy: Provavelmente vale a pena mudar a frase que afirma que este é um exemplo de "operações de bit", então.
Suponhamos que poucas coisas primeiro sejam num = 55 Integer para executar operações bit a bit (definir, obter, limpar, alternar). n = 4Posição de bit com base em 0 para executar operações bit a bit.
Como ficar um pouco?
Para obter o nthdeslocamento certo num, nvezes. Em seguida, execute AND bit a bit &com 1.
Realize complemento bit a bit com o resultado acima. Para que o enésimo bit fique desabilitado e o restante do bit fique definido, ou seja,~ (1 << n) .
Por fim, execute a operação AND bit a bit &com o resultado acima e num. Os três passos acima juntos podem ser escritos como num & (~ (1 << n));
num &=(~(1<< n));// Equivalent to; num = num & (~(1 << n));
Para alternar um pouco, usamos o ^operador XOR bit a bit . O operador XOR bit a bit avalia como 1 se o bit correspondente de ambos os operandos for diferente; caso contrário, avalia como 0.
O que significa alternar um pouco, precisamos executar a operação XOR com o bit que você deseja alternar e 1.
num ^=(1<< n);// Equivalent to; num = num ^ (1 << n);
Obrigado pela explicação detalhada. Aqui está o link para o problema prática para BIT Magia ligação
Chandra Shekhar
4
Como você define, limpa e alterna um único bit?
Para resolver uma armadilha comum de codificação ao tentar formar a máscara: 1nem sempre é grande o suficiente
Que problemas acontecem quando numberé do tipo mais amplo 1? xpode ser muito grande para a mudança que 1 << xleva ao comportamento indefinido (UB). Mesmo que xnão seja muito grande, ~pode não ser suficiente para gerar bits mais significativos.
// assume 32 bit int/unsignedunsignedlonglong number = foo();unsigned x =40;
number |=(1<< x);// UB
number ^=(1<< x);// UB
number &=~(1<< x);// UB
x =10;
number &=~(1<< x);// Wrong mask, not wide enough
Para garantir que 1 seja amplo o suficiente:
O código pode ser usado de forma 1ullpedanática (uintmax_t)1e permitir que o compilador otimize.
number |=(1ull<< x);
number |=((uintmax_t)1<< x);
Ou elenco - o que gera problemas de codificação / revisão / manutenção, mantendo o elenco correto e atualizado.
number |=(type_of_number)1<< x;
Ou promova gentilmente 1forçando uma operação matemática que seja tão larga quanto o tipo de number.
number |=(number*0+1)<< x;
Como a maioria das manipulações de bits, melhor trabalhar com não assinados tipos em vez de assinados os
Olhar interessante em uma pergunta antiga! Nem number |= (type_of_number)1 << x;nem number |= (number*0 + 1) << x;apropriadas para definir o bit de sinal de um tipo assinado ... Por uma questão de fato, nem é number |= (1ull << x);. Existe uma maneira portátil de fazer isso por posição?
chqrlie
1
@chqrlie IMO, a melhor maneira de evitar definir o bit de sinal e arriscar UB ou BID com turnos é usar tipos não assinados . O código assinado de turno altamente portátil é complicado demais para ser aceitável.
chux - Restabelece Monica
3
Uma versão do modelo C ++ 11 (colocada em um cabeçalho):
Este código está quebrado. (Além disso, por que você tem ;após suas definições de função?)
melpomene
@melpomene O código não está quebrado, eu testei. Você quer dizer que não será compilado ou que o resultado está errado? Sobre o extra ';' Não me lembro, eles podem ser removidos de fato.
Joakim L. Christiansen
(variable & bits == bits)?
Melpomene
Obrigado por perceber, era para ser((variable & bits) == bits)
Joakim L. Christiansen
use std::bitsetem c ++ 11
pqnet 25/10/19
0
Este programa é baseado na solução acima do @ Jeremy. Se alguém quiser brincar rapidamente.
Respostas:
Configurando um pouco
Use o operador OR bit a bit (
|
) para definir um pouco.Isso definirá o
n
th bit denumber
.n
deve ser zero, se você deseja definir o1
st bit e assim por dianten-1
, se deseja definir on
th bit.Use
1ULL
senumber
for maior queunsigned long
; a promoção de1UL << n
não acontece até depois de avaliar1UL << n
onde o comportamento indefinido muda mais do que a largura de umlong
. O mesmo se aplica a todo o restante dos exemplos.Limpando um pouco
Use o operador AND bit a bit (
&
) para limpar um pouco.Isso limpará o
n
th th denumber
. Você deve inverter a string de bits com o operador NOT bit a bit (~
) e depois AND.Alternando um pouco
O operador XOR (
^
) pode ser usado para alternar um pouco.Isso alternará o
n
th bit denumber
.Verificando um pouco
Você não pediu isso, mas eu poderia adicioná-lo.
Para verificar um pouco, desloque o número n para a direita e, em seguida, bit a bit E:
Isso colocará o valor do
n
th bitnumber
na variávelbit
.Alterando o n ésimo bit para x
Definir o
n
th bit como um1
ou0
pode ser alcançado com o seguinte na implementação C ++ de um complemento de 2:O bit
n
será definido sex
estiver1
e limpo sex
estiver0
. Sex
tiver algum outro valor, você recebe lixo.x = !!x
o booleanizará para 0 ou 1.Para tornar isso independente do comportamento de negação do complemento de 2 (onde
-1
todos os bits foram definidos, diferentemente do complemento de 1 ou da implementação de sinal / magnitude C ++), use negação não assinada.ou
Geralmente, é uma boa ideia usar tipos não assinados para manipulação portátil de bits.
ou
(number & ~(1UL << n))
irá limpar on
th bit e(x << n)
definirá on
th bit parax
.Também é geralmente uma boa idéia não copiar / colar código em geral e muitas pessoas usam macros de pré-processador (como a resposta do wiki da comunidade mais adiante ) ou algum tipo de encapsulamento.
fonte
bit = (number >> x) & 1
1
é umint
literal, que é assinado. Portanto, todas as operações aqui operam com números assinados, o que não é bem definido pelos padrões. Os padrões não garantem o complemento de dois ou a mudança aritmética, portanto é melhor usá-lo1U
.number = number & ~(1 << n) | (x << n);
Alterar o n-ésimo bit para x.Usando a biblioteca C ++ padrão:
std::bitset<N>
.Ou a versão Boost :
boost::dynamic_bitset
.Não há necessidade de criar o seu próprio:
A versão Boost permite um conjunto de bits do tamanho de tempo de execução em comparação com um conjunto de bits do tamanho de compilação da biblioteca padrão .
fonte
A outra opção é usar campos de bits:
define um campo de 3 bits (na verdade, são três campos de 1 bit). As operações de bit agora se tornam um pouco (haha) mais simples:
Para definir ou limpar um pouco:
Para alternar um pouco:
Verificando um pouco:
Isso funciona apenas com campos de bits de tamanho fixo. Caso contrário, você precisará recorrer às técnicas de manipulação de bits descritas nas postagens anteriores.
fonte
Eu uso macros definidas em um arquivo de cabeçalho para manipular o conjunto de bits e limpar:
fonte
BITMASK_CHECK(x,y) ((x) & (y))
deve ser((x) & (y)) == (y)
de outra forma retorna resultado incorreto na máscara multibit (ex.5
vs.3
/ * Olá a todos os coveiros:) * /)1
deve ser(uintmax_t)1
ou semelhantes no caso de alguém tentar usar essas macros em umlong
ou tipo maiorBITMASK_CHECK_ALL(x,y)
pode ser implementado como #!~((~(y))|(x))
!(~(x) & (y))
Às vezes vale a pena usar um
enum
para nomear os bits:Em seguida, use os nomes posteriormente. Ou seja, escrever
para definir, limpar e testar. Dessa forma, você oculta os números mágicos do restante do seu código.
Fora isso, eu apoio a solução de Jeremy.
fonte
clearbits()
função em vez de&= ~
. Por que você está usando um enum para isso? Eu pensei que eram para criar um monte de variáveis únicas com valor arbitrário oculto, mas você está atribuindo um valor definido para cada uma. Então, qual é o benefício versus apenas defini-los como variáveis?enum
s para conjuntos de constantes relacionadas remonta a um longo caminho na programação c. Eu suspeito que, com os compiladores modernos, a única vantagem sobreconst short
ou o que quer que seja é que eles estão explicitamente agrupados. E quando você quer que eles para algo outro do que bitmasks você começa a numeração automática. No c ++, é claro, eles também formam tipos distintos, o que fornece uma verificação extra de erros estáticos.enum ThingFlags
valorThingError|ThingFlag1
, por exemplo?int
. Isso pode causar todos os tipos de erros sutis devido à promoção de número inteiro implícito ou operações bit a bit em tipos assinados.thingstate = ThingFlag1 >> 1
por exemplo, chamará o comportamento definido pela implementação.thingstate = (ThingFlag1 >> x) << y
pode invocar um comportamento indefinido. E assim por diante. Para estar seguro, sempre faça a conversão para um tipo não assinado.enum My16Bits: unsigned short { ... };
Do bitops.h de snip-c.zip:
OK, vamos analisar as coisas ...
A expressão comum com a qual você parece estar tendo problemas em tudo isso é "(1L << (posn))". Tudo isso é criar uma máscara com um único bit ativado e que funcionará com qualquer tipo de número inteiro. O argumento "posn" especifica a posição em que você deseja o bit. Se posn == 0, esta expressão será avaliada para:
Se posn == 8, ele avaliará como:
Em outras palavras, ele simplesmente cria um campo de 0 com um 1 na posição especificada. A única parte complicada está na macro BitClr (), na qual precisamos definir um único 0 bit em um campo de 1's. Isso é feito usando o complemento 1 da mesma expressão, conforme indicado pelo operador til (~).
Depois que a máscara é criada, ela é aplicada ao argumento, como você sugere, usando os operadores bit a bit e (&), ou (|) e xor (^). Como a máscara é do tipo longa, as macros também funcionarão com caracteres char, short, int ou long.
A linha inferior é que esta é uma solução geral para toda uma classe de problemas. É claro que é possível e até apropriado reescrever o equivalente a qualquer uma dessas macros com valores explícitos de máscara toda vez que você precisar, mas por que fazer isso? Lembre-se de que a substituição da macro ocorre no pré-processador e, portanto, o código gerado refletirá o fato de que os valores são considerados constantes pelo compilador - ou seja, é tão eficiente usar as macros generalizadas quanto "reinventar a roda" toda vez que você precisar faça manipulação de bits.
Não convencido? Aqui está um código de teste - usei o Watcom C com otimização total e sem usar _cdecl para que a desmontagem resultante fosse a mais limpa possível:
---- [TEST.C] ----------------------------------------- -----------------------
---- [TEST.OUT (desmontado)] -------------------------------------- ---------
---- [finis] ------------------------------------------- ----------------------
fonte
arg
forlong long
.1L
precisa ser o tipo mais amplo possível(uintmax_t)1
. (Você pode se safar1ull
)Use os operadores bit a bit:
&
|
Para definir o último bit em
000b
:Para verificar o último bit
foo
:Para limpar o último bit em
foo
:Eu costumava ter
XXXb
clareza. Você provavelmente estará trabalhando com representação HEX, dependendo da estrutura de dados na qual está compactando bits.fonte
foo = foo ^ MY_MASK
foo = foo & ~MY_MASK
Para o iniciante, gostaria de explicar um pouco mais com um exemplo:
Exemplo:
O
&
operador é usado, verifique o bit:Alternar ou Inverter:
|
operador: defina o bitfonte
Aqui está minha macro aritmética de bits favorita, que funciona para qualquer tipo de matriz inteira não assinada de
unsigned char
atésize_t
(que é o maior tipo que deve ser eficiente para trabalhar):Para definir um pouco:
Para limpar um pouco:
Para alternar um pouco:
Para testar um pouco:
etc.
fonte
BITOP(array, bit++, |=);
em loop provavelmente não fará o que o chamador deseja.BITCELL(a,b) |= BITMASK(a,b);
(ambos usama
como argumento para determinar o tamanho, mas o último nunca avaliariaa
desde aparece apenas emsizeof
).(size_t)
elenco parecem estar lá apenas para segurar alguns matemática não assinado com%
. Poderia(unsigned)
lá.(size_t)(b)/(8*sizeof *(a))
desnecessariamente poderia diminuirb
antes da divisão. Apenas um problema com matrizes de bits muito grandes. Ainda uma macro interessante.Como isso está marcado como "incorporado", assumirei que você está usando um microcontrolador. Todas as sugestões acima são válidas e funcionam (leitura-modificação-gravação, uniões, estruturas, etc.).
No entanto, durante um período de depuração baseada em osciloscópio, fiquei surpreso ao descobrir que esses métodos têm uma sobrecarga considerável nos ciclos da CPU em comparação com a gravação de um valor diretamente nos registros PORTnSET / PORTnCLEAR do micro, o que faz uma diferença real quando existem loops estreitos / altos pinos de alternância do ISR de alta frequência.
Para quem não conhece: No meu exemplo, o micro possui um registro geral de estado de pino PORTn, que reflete os pinos de saída, e PORTn | = BIT_TO_SET resulta em uma leitura-modificação-gravação no registro. No entanto, os registradores PORTnSET / PORTnCLEAR levam um '1' para significar "por favor, faça este bit 1" (SET) ou "por favor, faça este bit zero" (CLEAR) e um '0' para significar "deixe o pino em paz". portanto, você acaba com dois endereços de porta, dependendo de definir ou limpar o bit (nem sempre é conveniente), mas uma reação muito mais rápida e um código montado menor.
fonte
volatile
e, portanto, o compilador não pode executar nenhuma otimização no código que envolve esses registros. Portanto, é uma boa prática desmontar esse código e ver como ficou no nível do assembler.A abordagem de campo de bits tem outras vantagens na arena incorporada. Você pode definir uma estrutura que mapeie diretamente os bits em um registro de hardware específico.
Você precisa estar ciente da ordem de compactação de bits - acho que é o MSB primeiro, mas isso pode depender da implementação. Além disso, verifique como os campos de manipuladores do compilador cruzam os limites de bytes.
Você pode então ler, escrever, testar os valores individuais como antes.
fonte
Verifique um pouco em um local arbitrário em uma variável do tipo arbitrário:
Uso da amostra:
Notas: Ele foi projetado para ser rápido (dada sua flexibilidade) e não ramificado. Isso resulta em um código de máquina SPARC eficiente quando compilado o Sun Studio 8; Também testei usando o MSVC ++ 2008 em amd64. É possível criar macros semelhantes para definir e limpar bits. A principal diferença desta solução em comparação com muitas outras aqui é que ela funciona para qualquer local em praticamente qualquer tipo de variável.
fonte
Mais geral, para bitmaps de tamanho arbitrário:
fonte
CHAR_BIT
já está definido porlimits.h
, você não precisa colocar no seu próprioBITS
(e na verdade você piorar seu código ao fazê-lo)Este programa deve alterar qualquer bit de dados de 0 para 1 ou 1 para 0:
fonte
Se você está mexendo bastante, talvez queira usar máscaras, o que tornará tudo mais rápido. As funções a seguir são muito rápidas e ainda são flexíveis (elas permitem rodar bit em bit maps de qualquer tamanho).
Observe que, para definir o bit 'n' em um número inteiro de 16 bits, faça o seguinte:
Cabe a você garantir que o número de bits esteja dentro do intervalo do mapa de bits que você passa. Observe que, para pequenos processadores endian, que bytes, palavras, dwords, qwords etc. são mapeados corretamente um para o outro na memória (principal motivo pelo qual os pequenos processadores endian são 'melhores' que os processadores big endian, ah, sinto uma guerra de chamas chegando em...).
fonte
Usa isto:
fonte
Expandindo a
bitset
resposta:fonte
Se você deseja executar todas essas operações com programação C no kernel do Linux , sugiro usar APIs padrão do kernel do Linux.
Veja https://www.kernel.org/doc/htmldocs/kernel-api/ch02s03.html
Nota: Aqui toda a operação acontece em uma única etapa. Portanto, todos eles são garantidos como atômicos, mesmo em computadores SMP, e são úteis para manter a coerência entre os processadores.
fonte
O Visual C 2010, e talvez muitos outros compiladores, têm suporte direto para operações booleanas incorporadas. Um bit tem dois valores possíveis, assim como um booleano, para que possamos usar booleanos - mesmo que ocupem mais espaço do que um único bit. memória nesta representação. Isso funciona, até o
sizeof()
operador funciona corretamente.Portanto, para sua pergunta,
IsGph[i] =1
ouIsGph[i] =0
facilite a configuração e limpeza de bools.Para encontrar caracteres não imprimíveis:
Observe que não há nada de "especial" nesse código. Trata-se um pouco como um número inteiro - o que tecnicamente é. Um número inteiro de 1 bit que pode conter 2 valores e apenas 2 valores.
Uma vez, usei essa abordagem para encontrar registros duplicados de empréstimos, em que loan_number era a chave ISAM, usando o número de empréstimo de 6 dígitos como índice na matriz de bits. Savagely rápido, e após 8 meses, provou que o sistema de mainframe do qual estávamos obtendo os dados estava de fato com defeito. A simplicidade das matrizes de bits torna a confiança em sua correção muito alta - em comparação com uma abordagem de pesquisa, por exemplo.
fonte
bool
. Talvez até 4 bytes para configurações C89 que usamint
para implementarbool
Use um dos operadores, conforme definido aqui .
Para definir um bit, usado
int x = x | 0x?;
onde?
está a posição do bit em formato binário.fonte
0x
é o prefixo para um literal em hexadecimal, não binário.Aqui estão algumas macros que eu uso:
fonte
Variável usada
value - Data
pos - posição do bit que estamos interessados em definir, limpar ou alternar.
Defina um pouco:
Limpe um pouco:
Alterne um pouco:
fonte
fonte
check_nth_bit
pode serbool
.Como ficar um pouco?
nth
deslocamento certonum
,n
vezes. Em seguida, execute AND bit a bit&
com 1.Como funciona?
Como definir um pouco?
n
vezes. Em seguida, execute a operação OR bit a bit|
comnum
.Como funciona?
Como limpar um pouco?
n
vezes ie1 << n
.~ (1 << n)
.&
com o resultado acima enum
. Os três passos acima juntos podem ser escritos comonum & (~ (1 << n))
;Como funciona?
Como alternar um pouco?
Para alternar um pouco, usamos o
^
operador XOR bit a bit . O operador XOR bit a bit avalia como 1 se o bit correspondente de ambos os operandos for diferente; caso contrário, avalia como 0.O que significa alternar um pouco, precisamos executar a operação XOR com o bit que você deseja alternar e 1.
Como funciona?
0 ^ 1 => 1
.1 ^ 1 => 0
.Leitura recomendada - Exercícios do operador Bitwise
fonte
Para resolver uma armadilha comum de codificação ao tentar formar a máscara:
1
nem sempre é grande o suficienteQue problemas acontecem quando
number
é do tipo mais amplo1
?x
pode ser muito grande para a mudança que1 << x
leva ao comportamento indefinido (UB). Mesmo quex
não seja muito grande,~
pode não ser suficiente para gerar bits mais significativos.Para garantir que 1 seja amplo o suficiente:
O código pode ser usado de forma
1ull
pedanática(uintmax_t)1
e permitir que o compilador otimize.Ou elenco - o que gera problemas de codificação / revisão / manutenção, mantendo o elenco correto e atualizado.
Ou promova gentilmente
1
forçando uma operação matemática que seja tão larga quanto o tipo denumber
.Como a maioria das manipulações de bits, melhor trabalhar com não assinados tipos em vez de assinados os
fonte
number |= (type_of_number)1 << x;
nemnumber |= (number*0 + 1) << x;
apropriadas para definir o bit de sinal de um tipo assinado ... Por uma questão de fato, nem énumber |= (1ull << x);
. Existe uma maneira portátil de fazer isso por posição?Uma versão do modelo C ++ 11 (colocada em um cabeçalho):
fonte
;
após suas definições de função?)(variable & bits == bits)
?((variable & bits) == bits)
std::bitset
em c ++ 11Este programa é baseado na solução acima do @ Jeremy. Se alguém quiser brincar rapidamente.
fonte
Tente uma destas funções na linguagem C para alterar n bit:
Ou
Ou
fonte
value << n
pode causar comportamento indefinido