Posso usar um literal binário em C ou C ++?

190

Eu preciso trabalhar com um número binário.

Eu tentei escrever:

const x = 00010000;

Mas não deu certo.

Sei que posso usar um número hexadecimal com o mesmo valor 00010000, mas quero saber se existe um tipo em C ++ para números binários e, se não houver, existe outra solução para o meu problema?

hamza
fonte
51
Você sabe que 00010000é octal, certo? (E a sua declaração está faltando um tipo.)
Keith Thompson
Aqui maneira moderna usando literais C ++.
Lol4t0
2
O C ++ 14 adicionou um recurso para isso. Veja minha nova resposta para mais detalhes na parte inferior. Obviamente, requer um compilador que o implemente.
Lpapp
1
@FormlessCloud: Essas são as regras de sintaxe fornecidas nos padrões C e C ++ ( 0baparecem apenas no C ++ 14). Eles são projetados para serem inequívocos.
Keith Thompson
2
Possível duplicata de literais binários?
MJ Rayburn #

Respostas:

70

Você pode usarBOOST_BINARY enquanto aguarda C ++ 0x. :) BOOST_BINARYsem dúvida tem uma vantagem sobre a implementação do modelo, na medida em que também pode ser usado em programas C (é 100% direcionado ao pré-processador).

Para fazer o inverso (ou seja, imprimir um número em formato binário), você pode usar a itoafunção não portátil ou implementar a sua própria .

Infelizmente, você não pode fazer a formatação da base 2 com fluxos STL (já setbaseque apenas honrará as bases 8, 10 e 16), mas você pode usar uma std::stringversão itoaou (a mais concisa, mas marginalmente menos eficiente) std::bitset.

#include <boost/utility/binary.hpp>
#include <stdio.h>
#include <stdlib.h>
#include <bitset>
#include <iostream>
#include <iomanip>

using namespace std;

int main() {
  unsigned short b = BOOST_BINARY( 10010 );
  char buf[sizeof(b)*8+1];
  printf("hex: %04x, dec: %u, oct: %06o, bin: %16s\n", b, b, b, itoa(b, buf, 2));
  cout << setfill('0') <<
    "hex: " << hex << setw(4) << b << ", " <<
    "dec: " << dec << b << ", " <<
    "oct: " << oct << setw(6) << b << ", " <<
    "bin: " << bitset< 16 >(b) << endl;
  return 0;
}

produz:

hex: 0012, dec: 18, oct: 000022, bin:            10010
hex: 0012, dec: 18, oct: 000022, bin: 0000000000010010

Leia também Os Formadores de Cordas da Manor Farm, de Herb Sutter, para uma discussão interessante.

vladr
fonte
2
Como diz a própria página à qual você vincula, você pode usar apenas 8, 10 ou 16 com o setbase. No entanto:int main() { cout << bitset<8>(42); }
@ Roger Obrigado pela bitsetdica, eu já corrigi um pouco sobresetbase antes de ver seu comentário.
vladr
Aqui está um tutorial sobre literais definidos pelo usuário no c ++ 11: akrzemi1.wordpress.com/2012/10/23/user-defined-literals-part-ii . Evidentemente, c ++ 1y (também conhecido como c ++ 14) incluirá literais binários no padrão.
Cheshirekow #
274

Se você estiver usando o GCC, poderá usar uma extensão do GCC (incluída no padrão C ++ 14 ) para isso:

int x = 0b00010000;
qrdl
fonte
2
Vários outros compiladores têm este ou outros meios similares de expressar números na base 2.
nategoose
4
Seria bom ter isso padronizado, mas o clang suporta a mesma notação.
precisa saber é
14
Funciona em Clang, GCC e TCC. Não funciona no PCC. Não tenho nenhum outro compilador para testar.
Michas
6
Eu já vi vários compiladores de sistemas embarcados que o suportam. Não conheço nenhum motivo em particular que não deva ser um recurso de idioma padrão.
Supercat 01/08
5
@polemon open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3472.pdf (C ++ 14.)
Jonathan Baldwin
98

Você pode usar literais binários. Eles são padronizados em C ++ 14. Por exemplo,

int x = 0b11000;

Suporte no GCC

O suporte no GCC começou no GCC 4.3 (consulte https://gcc.gnu.org/gcc-4.3/changes.html ) como extensões da família de idiomas C (consulte https://gcc.gnu.org/onlinedocs/gcc/ C-Extensions.html # C-Extensions ), mas desde o GCC 4.9, agora ele é reconhecido como um recurso do C ++ 14 ou como uma extensão (consulte Diferença entre literais binários do GCC e C ++ 14? )

Suporte no Visual Studio

O suporte no Visual Studio foi iniciado no Visual Studio 2015 Preview (consulte https://www.visualstudio.com/news/vs2015-preview-vs#C++ ).

Mohamed El-Nakib
fonte
5
Você pode usar 'para separar cada parte: "0b0000'0100'0100'0001
camino
1
@camino Bom, você pode perder o primeiro "
Nikos
Essa deve ser a resposta aceita. A maioria das outras respostas está tão desatualizada.
Alex
73
template<unsigned long N>
struct bin {
    enum { value = (N%10)+2*bin<N/10>::value };
} ;

template<>
struct bin<0> {
    enum { value = 0 };
} ;

// ...
    std::cout << bin<1000>::value << '\n';

O dígito mais à esquerda do literal ainda precisa ser 1, mas mesmo assim.

wilhelmtell
fonte
4
Versão melhor: bitbucket.org/kniht/scraps/src/tip/cpp/binary.hpp ( binary<10>::value == binary<010>::valuee alguns verificação de erros)
De alguma forma, perdi essa antes de postar minha resposta quase idêntica. Mas no meu primeiro dígito tem que ser 0, não 1.
Mark Ransom
4
Uma versão melhor dessa ideia de modelo: code.google.com/p/cpp-binary-constants
Valentin Galea
@ValentinGalea - por que a versão do Google é melhor que isso?
AJed
Isso é impressionante. Pena que não funciona para um grande número de bits.
A Quantum Físico
31

Alguns compiladores (geralmente aqueles para microcontroladores ) possuem um recurso especial implementado no reconhecimento de números binários literais pelo prefixo "0b ..." que precede o número, embora a maioria dos compiladores (padrões C / C ++) não possuam esse recurso e, se é o caso, aqui está minha solução alternativa:

#define B_0000    0
#define B_0001    1
#define B_0010    2
#define B_0011    3
#define B_0100    4
#define B_0101    5
#define B_0110    6
#define B_0111    7
#define B_1000    8
#define B_1001    9
#define B_1010    a
#define B_1011    b
#define B_1100    c
#define B_1101    d
#define B_1110    e
#define B_1111    f

#define _B2H(bits)    B_##bits
#define B2H(bits)    _B2H(bits)
#define _HEX(n)        0x##n
#define HEX(n)        _HEX(n)
#define _CCAT(a,b)    a##b
#define CCAT(a,b)   _CCAT(a,b)

#define BYTE(a,b)        HEX( CCAT(B2H(a),B2H(b)) )
#define WORD(a,b,c,d)    HEX( CCAT(CCAT(B2H(a),B2H(b)),CCAT(B2H(c),B2H(d))) )
#define DWORD(a,b,c,d,e,f,g,h)    HEX( CCAT(CCAT(CCAT(B2H(a),B2H(b)),CCAT(B2H(c),B2H(d))),CCAT(CCAT(B2H(e),B2H(f)),CCAT(B2H(g),B2H(h)))) )

// Using example
char b = BYTE(0100,0001); // Equivalent to b = 65; or b = 'A'; or b = 0x41;
unsigned int w = WORD(1101,1111,0100,0011); // Equivalent to w = 57155; or w = 0xdf43;
unsigned long int dw = DWORD(1101,1111,0100,0011,1111,1101,0010,1000); //Equivalent to dw = 3745774888; or dw = 0xdf43fd28;

Desvantagens (não são grandes):

  • Os números binários devem ser agrupados 4 por 4;
  • Os literais binários devem ser apenas números inteiros não assinados;

Vantagens :

  • Total do pré-processador direcionado, não spending processor timeem operações inúteis ( like "?.. :..", "<<", "+") ao programa executável (pode ser executado centenas de vezes no aplicativo final);
  • Também funciona com "mainly in C"compiladores e C ++ ( template+enum solution works only in C++ compilers);
  • Ele tem apenas a limitação de "longitude" para expressar valores "constantes literais". Teria havido limitação de longitude precoce (geralmente 8 bits: 0-255) se alguém tivesse expressado valores constantes analisando a resolução de "enum solution" (usually 255 = reach enum definition limit), diferentemente, limitações "constantes literais", no compilador permite números maiores;
  • Algumas outras soluções exigem um número exagerado de definições constantes (muitas definem na minha opinião), incluindo longas ou several header files(na maioria dos casos, não são facilmente legíveis e compreensíveis, e tornam o projeto desnecessariamente confuso e estendido, como o uso "BOOST_BINARY()");
  • Simplicidade da solução: facilmente legível, compreensível e ajustável para outros casos (pode ser estendido para agrupar 8 por 8 também);
Renato Chandelier
fonte
Por que, por exemplo, B_0100não é usado (em vez de 0100)? Como em eg char b = BYTE(0100,0001);.
Peter Mortensen
@PeterMortensen O B_ é adicionado pela _B2Hfunção de pré - processador.
Mxmlnkn 26/10/19
20

Este tópico pode ajudar.

/* Helper macros */
#define HEX__(n) 0x##n##LU
#define B8__(x) ((x&0x0000000FLU)?1:0) \
+((x&0x000000F0LU)?2:0) \
+((x&0x00000F00LU)?4:0) \
+((x&0x0000F000LU)?8:0) \
+((x&0x000F0000LU)?16:0) \
+((x&0x00F00000LU)?32:0) \
+((x&0x0F000000LU)?64:0) \
+((x&0xF0000000LU)?128:0)

/* User macros */
#define B8(d) ((unsigned char)B8__(HEX__(d)))
#define B16(dmsb,dlsb) (((unsigned short)B8(dmsb)<<8) \
+ B8(dlsb))
#define B32(dmsb,db2,db3,dlsb) (((unsigned long)B8(dmsb)<<24) \
+ ((unsigned long)B8(db2)<<16) \
+ ((unsigned long)B8(db3)<<8) \
+ B8(dlsb))


#include <stdio.h>

int main(void)
{
    // 261, evaluated at compile-time
    unsigned const number = B16(00000001,00000101);

    printf("%d \n", number);
    return 0;
}

Funciona! (Todos os créditos vão para Tom Torfs.)

Federico A. Ramponi
fonte
i realmente não entendo (IMA iniciante em programação e especialmente em C ++), mas parece interessante por isso vou tentar compreendê-lo depois de alguns estudos mais C ++, graças
Hamza
3
A macro B8 funciona convertendo o literal "binário" em um literal hexadecimal e extraindo a cada 4 bits.
dan04
Gostaria de saber o que 0x ## n ## LU significa? Nunca encontrou essa sintaxe.
Federico A. Ramponi
@hamza: é realmente bastante complicado. Mas o que você precisa entender é apenas a partir de #include <stdio>.
Federico A. Ramponi
8
@Federico: o ##operador do pré-processador cola os tokens juntos. Portanto, nesse caso, se você ligar HEX__(10), ele se expandirá para 0x10LU.
James McNellis
18

Como já foi respondido, os padrões C não têm como escrever diretamente números binários. Existem extensões do compilador, no entanto, e aparentemente o C ++ 14 inclui o 0bprefixo para o binário. (Observe que esta resposta foi publicada originalmente em 2010.)

Uma solução popular é incluir um arquivo de cabeçalho com macros auxiliares . Uma opção fácil também é gerar um arquivo que inclua definições de macro para todos os padrões de 8 bits, por exemplo:

#define B00000000 0
#define B00000001 1
#define B00000010 2

Isso resulta em apenas 256 #defines e, se forem necessárias constantes binárias maiores que 8 bits, essas definições poderão ser combinadas com turnos e ORs, possivelmente com macros auxiliares (por exemplo,BIN16(B00000001,B00001010) ). (Ter macros individuais para cada valor de 16 bits, quanto mais 32 bits, não é plausível.)

Obviamente, a desvantagem é que essa sintaxe requer a gravação de todos os zeros à esquerda, mas isso também pode tornar mais claro o uso de configurações de sinalizadores de bits e conteúdo de registros de hardware. Para uma macro de função que resulta em uma sintaxe sem essa propriedade, consulte o bithacks.hlink acima.

Arkku
fonte
2
Então, qual o tamanho de um arquivo que o CPP precisaria ler se você tivesse todas as macros para um long long int?
precisa saber é o seguinte
3
@wilhelmtell: E qual é a relevância disso quando especifiquei “todos os padrões de 8 bits ” (= 256 linhas) e sugeri combinar quantidades maiores desses? Mesmo o BOOST_BINARY da resposta aceita define todos os padrões de 8 bits no cabeçalho ...
Arkku
16

A mentalidade de excesso de engenharia do C ++ já está bem explicada nas outras respostas aqui. Aqui está minha tentativa de fazê-lo com uma mentalidade C, mantenha-o-simples-ffs:

unsigned char x = 0xF; // binary: 00001111
Craig
fonte
12

C não possui notação nativa para números binários puros. Sua melhor aposta aqui seria octal (por exemplo 07777) de hexadecimal (por exemplo 0xfff).

Nikolai Fetissov
fonte
11

Você pode usar a função encontrada nesta pergunta para obter até 22 bits em C ++. Aqui está o código do link, devidamente editado:

template< unsigned long long N >
struct binary
{
  enum { value = (N % 8) + 2 * binary< N / 8 > :: value } ;
};

template<>
struct binary< 0 >
{
  enum { value = 0 } ;
};

Então você pode fazer algo parecido binary<0101011011>::value.

Mark Ransom
fonte
7

A menor unidade com a qual você pode trabalhar é um byte (que é do chartipo). Você pode trabalhar com bits usando operadores bit a bit.

Quanto aos literais inteiros, você só pode trabalhar com números decimais (base 10), octal (base 8) ou hexadecimais (base 16). Não há literais binários (base 2) em C nem C ++.

Os números octais são prefixados 0e os números hexadecimais são prefixados 0x. Números decimais não têm prefixo.

No C ++ 0x, você poderá fazer o que quiser por meio de literais definidos pelo usuário .

Brian R. Bondy
fonte
posso pelo menos mostrar o valor binário de um hexadecimal em uma função de impressão ou cout?
hamza
Sim, você pode <shameless_plug> stackoverflow.com/questions/2611764#2611883 </shameless_plug>
vladr
5
Alguns compiladores C suportam 0b100101 para literais binários, mas infelizmente é uma extensão fora do padrão.
Joey Adams
3
Observe que, embora não esteja definido no padrão, alguns compiladores (principalmente os para microcontroladores e sistemas embarcados) adicionam a sintaxe para binário no formato 0b00101010como uma conveniência. O SDCC é um deles, e tenho certeza de que existem outros também. (Edit: Hah, chegou antes de mim, @Joey!)
Matt B.
5

Você também pode usar montagem embutida como esta:

int i;

__asm {
    mov eax, 00000000000000000000000000000000b
    mov i,   eax
}

std::cout << i;

Ok, pode ser um pouco exagerado, mas funciona.

renger
fonte
3
Sua solução não é multiplataforma. Em muitas arquiteturas, você não pode incluir o código de montagem em C. Especificamente no compilador do Microsoft Visual studio, é possível (quando compilado para x86 32bits). Mas como você sabe se o seu processador possui um registro 'eax'? Pense nos processadores ARM em telefones celulares, processadores x64 etc. Eles não têm 'eax'. Processador MIPS não tem sequer 'mov' comando
DanielHsH
4

Com base em outras respostas, mas esta rejeitará programas com literais binários ilegais. Os zeros à esquerda são opcionais.

template<bool> struct BinaryLiteralDigit;

template<> struct BinaryLiteralDigit<true> {
    static bool const value = true;
};

template<unsigned long long int OCT, unsigned long long int HEX>
struct BinaryLiteral {
    enum {
        value = (BinaryLiteralDigit<(OCT%8 < 2)>::value && BinaryLiteralDigit<(HEX >= 0)>::value
            ? (OCT%8) + (BinaryLiteral<OCT/8, 0>::value << 1)
            : -1)
    };
};

template<>
struct BinaryLiteral<0, 0> {
    enum {
        value = 0
    };
};

#define BINARY_LITERAL(n) BinaryLiteral<0##n##LU, 0x##n##LU>::value

Exemplo:

#define B BINARY_LITERAL

#define COMPILE_ERRORS 0

int main (int argc, char ** argv) {
    int _0s[] = { 0, B(0), B(00), B(000) };
    int _1s[] = { 1, B(1), B(01), B(001) };
    int _2s[] = { 2, B(10), B(010), B(0010) };
    int _3s[] = { 3, B(11), B(011), B(0011) };
    int _4s[] = { 4, B(100), B(0100), B(00100) };

    int neg8s[] = { -8, -B(1000) };

#if COMPILE_ERRORS
    int errors[] = { B(-1), B(2), B(9), B(1234567) };
#endif

    return 0;
}
Thomas Eding
fonte
3

O "tipo" de um número binário é igual a qualquer número decimal, hexadecimal ou octal: int (ou mesmo char, short, long long).

Quando você atribui uma constante, não pode atribuí-la com 11011011 (curiosa e infelizmente), mas pode usar hex. Hex é um pouco mais fácil de traduzir mentalmente. Pedaços de mordidelas (4 bits) e traduza para um caractere em [0-9a-f].

Stephen
fonte
2

Você pode usar um conjunto de bits

bitset<8> b(string("00010000"));
int i = (int)(bs.to_ulong());
cout<<i;
Deqing
fonte
2

Estendi a boa resposta dada por @ renato-chandelier, garantindo o apoio de:

  • _NIBBLE_(…) - 4 bits, 1 mordidela como argumento
  • _BYTE_(…) - 8 bits, 2 mordidelas como argumentos
  • _SLAB_(…) - 12 bits, 3 mordidelas como argumentos
  • _WORD_(…) - 16 bits, 4 mordidelas como argumentos
  • _QUINTIBBLE_(…) - 20 bits, 5 petiscos como argumentos
  • _DSLAB_(…) - 24 bits, 6 petiscos como argumentos
  • _SEPTIBBLE_(…) - 28 bits, 7 petiscos como argumentos
  • _DWORD_(…) - 32 bits, 8 petiscos como argumentos

Na verdade, não tenho tanta certeza sobre os termos "quintebble" e "septibble". Se alguém conhece alguma alternativa, por favor me avise.

Aqui está a macro reescrita:

#define __CAT__(A, B) A##B
#define _CAT_(A, B) __CAT__(A, B)

#define __HEX_0000 0
#define __HEX_0001 1
#define __HEX_0010 2
#define __HEX_0011 3
#define __HEX_0100 4
#define __HEX_0101 5
#define __HEX_0110 6
#define __HEX_0111 7
#define __HEX_1000 8
#define __HEX_1001 9
#define __HEX_1010 a
#define __HEX_1011 b
#define __HEX_1100 c
#define __HEX_1101 d
#define __HEX_1110 e
#define __HEX_1111 f

#define _NIBBLE_(N1) _CAT_(0x, _CAT_(__HEX_, N1))
#define _BYTE_(N1, N2) _CAT_(_NIBBLE_(N1), _CAT_(__HEX_, N2))
#define _SLAB_(N1, N2, N3) _CAT_(_BYTE_(N1, N2), _CAT_(__HEX_, N3))
#define _WORD_(N1, N2, N3, N4) _CAT_(_SLAB_(N1, N2, N3), _CAT_(__HEX_, N4))
#define _QUINTIBBLE_(N1, N2, N3, N4, N5) _CAT_(_WORD_(N1, N2, N3, N4), _CAT_(__HEX_, N5))
#define _DSLAB_(N1, N2, N3, N4, N5, N6) _CAT_(_QUINTIBBLE_(N1, N2, N3, N4, N5), _CAT_(__HEX_, N6))
#define _SEPTIBBLE_(N1, N2, N3, N4, N5, N6, N7) _CAT_(_DSLAB_(N1, N2, N3, N4, N5, N6), _CAT_(__HEX_, N7))
#define _DWORD_(N1, N2, N3, N4, N5, N6, N7, N8) _CAT_(_SEPTIBBLE_(N1, N2, N3, N4, N5, N6, N7), _CAT_(__HEX_, N8))

E aqui está o exemplo de Renato:

char b = _BYTE_(0100, 0001); /* equivalent to b = 65; or b = 'A'; or b = 0x41; */
unsigned int w = _WORD_(1101, 1111, 0100, 0011); /* equivalent to w = 57155; or w = 0xdf43; */
unsigned long int dw = _DWORD_(1101, 1111, 0100, 0011, 1111, 1101, 0010, 1000); /* Equivalent to dw = 3745774888; or dw = 0xdf43fd28; */
madmurphy
fonte
0

Basta usar a biblioteca padrão em C ++:

#include <bitset>

Você precisa de uma variável do tipo std::bitset:

std::bitset<8ul> x;
x = std::bitset<8>(10);
for (int i = x.size() - 1; i >= 0; i--) {
      std::cout << x[i];
}

Neste exemplo, eu armazenei a forma binária de 10inx .

8uldefine o tamanho dos seus bits, então 7ulsignifica sete bits e assim por diante.

Hadi Rasekh
fonte
-1

C ++ fornece um modelo padrão chamado std::bitset. Experimente se quiser.

Summer_More_More_Tea
fonte
-9

Você pode tentar usar uma matriz de bool:

bool i[8] = {0,0,1,1,0,1,0,1}
george wagenknecht
fonte
1
Muitos votos negativos, sem explicação. Aqui está sua explicação: stackoverflow.com/questions/2064550/c-why-bool-is-8-bits-long Além disso, cada elemento em uma matriz está em um endereço de memória diferente. Mas queremos uma sequência de 1 e 0 compactados em um endereço.
JMI MADISON