Можно ли использовать бинарный литерал в C или С++?

Мне нужно работать с двоичным числом.

Я пробовал писать:

const x = 00010000;

Но это не сработало.

Я знаю, что я могу использовать шестнадцатеричное число, имеющее то же значение, что и 00010000, но я хочу знать, есть ли тип в С++ для двоичных чисел, а если нет, есть ли еще одно решение для моего проблема?

Ответ 1

Вы можете использовать BOOST_BINARY во время ожидания С++ 0x. :) BOOST_BINARY, возможно, имеет преимущество перед реализацией шаблонов, поскольку его можно использовать и в программах на C (он на 100% управляется препроцессором.)

Чтобы сделать обратное (то есть распечатать число в двоичной форме), вы можете использовать непереносимую функцию itoa или реализовать свою собственную.

К сожалению, вы не можете выполнить форматирование базы 2 с потоками STL (поскольку setbase будет учитывать только базы 8, 10 и 16), но вы можете использовать либо версию std::string itoa, либо ( более кратким, но несколько менее эффективным) 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;
}

производит:

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

Также прочитайте Херба Саттера The String Formatters of Manor Farm для интересного обсуждения.

Ответ 3

Вы можете использовать бинарные литералы. Они стандартизованы в С++ 14. Например,

int x = 0b11000;

Поддержка в GCC

Поддержка в GCC началась в GCC 4.3 (см. https://gcc.gnu.org/gcc-4.3/changes.html) в качестве расширений для семейства языков C (см. https://gcc.gnu.org/onlinedocs/gcc/C-Extensions.html#C-Extensions), но поскольку GCC 4.9 теперь распознается либо как функция С++ 14, либо расширение (см. Разница между бинарными литералами GCC и С++ 14?

Поддержка в Visual Studio

Поддержка в Visual Studio началась с предварительного просмотра Visual Studio 2015 (см. https://www.visualstudio.com/news/vs2015-preview-vs#C++).

Ответ 4

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';

Самая левая цифра литерала все равно должна быть 1, но тем не менее.

Ответ 5

Несколько компиляторов (как правило, для микроконтроллеров) имеет специальную функцию, реализованную в распознавании буквенных двоичных чисел префиксом "0b..." предшествующий числу, хотя большинство компиляторов (стандарты C/С++) не имеют такой функции, и, если это так, здесь это мое альтернативное решение:

#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;

Недостатки (это не такие большие):

  • Двоичные числа должны быть сгруппированы 4 на 4;
  • Бинарные литералы должны быть только целыми числами без знака;

<сильные > Преимущества:

  • Выполняется полный препроцессор, а не spending processor time в бессмысленных операциях (like "?.. :..", "<<", "+") в исполняемую программу (это может выполняться сто раз в конечном приложении);
  • Он также выполняет компиляторы "mainly in C" и С++ (template+enum solution works only in C++ compilers);
  • Он имеет только ограничение "долготы" для выражения значений "буквальной константы". Было бы раннее ограничение долготы (обычно 8 бит: 0-255), если бы они выражали постоянные значения, анализируя решение "enum solution" (usually 255 = reach enum definition limit), иначе говоря, ограничения "буквальной константы", в компиляторе разрешено большее число;
  • Некоторые другие решения требуют преувеличенного количества постоянных определений (на мой взгляд, слишком много определений), включая long или several header files (в большинстве случаев они не легко читаемы и понятны, а делают проект излишне запутанным и расширенным, например, используя "BOOST_BINARY()");
  • Простота решения: легко читаемая, понятная и настраиваемая для других случаев (может быть расширена и для группировки 8 на 8);

Ответ 6

Этот поток может помочь.

/* 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;
}

Это работает! (Все кредиты отправляются Тому Торфсу.)

Ответ 7

Как уже было сказано, стандарты C не имеют возможности напрямую писать двоичные числа. Однако есть расширения компилятора, и, судя по всему, С++ 14 содержит префикс 0b для двоичного кода. (Обратите внимание, что этот ответ был первоначально опубликован в 2010 году.)

Одним из распространенных способов решения проблемы является включение файла заголовка со вспомогательными макросами. Один простой вариант - также создать файл, который включает определения макросов для всех 8-битных шаблонов, например:

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

Это приводит только к 256 #define s, и если требуется больше 8-битных двоичных констант, эти определения могут быть объединены со сдвигами и OR, возможно, с вспомогательными макросами (например, BIN16(B00000001,B00001010)). (Наличие индивидуальных макросов для каждого 16-битного, не говоря уже о 32-битном значении, не правдоподобно.)

Конечно, недостатком является то, что этот синтаксис требует записи всех ведущих нулей, но это также может сделать его более понятным для использования, например, для установки бит-бит и содержимого аппаратных регистров. Для функционально-подобного макроса, приводящего к синтаксису без этого свойства, см. Ссылку bithacks.h, приведенную выше.

Ответ 8

Сверхпромышленное мышление С++ уже хорошо отражено в других ответах здесь. Здесь моя попытка сделать это с помощью C, keep-it-simple-ffs mindset:

unsigned char x = 0xF; // binary: 00001111

Ответ 9

C не имеет встроенной записи для чистых двоичных чисел. Лучше всего здесь будет восьмеричный (например, 07777) шестнадцатеричный (например, 0xfff).

Ответ 10

Вы можете использовать найденную функцию в этом вопросе, чтобы получить до 22 бит на С++. Здесь код из ссылки, соответствующим образом отредактированный:

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

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

Итак, вы можете сделать что-то вроде binary<0101011011>::value.

Ответ 11

Самая маленькая единица, с которой вы можете работать, - это байт (который имеет тип char). Вы можете работать с битами, хотя с помощью побитовых операторов.

Как и для целочисленных литералов, вы можете работать только с десятичными (базовыми 10), восьмеричными (базовыми 8) или шестнадцатеричными (базовыми 16) числами. В C или С++ нет бинарных (базовых 2) литералов.

Октальные числа имеют префикс 0, а шестнадцатеричные числа имеют префикс 0x. Десятичные числа не имеют префикса.

В С++ 0x вы сможете сделать то, что хотите, через пользовательские литералы.

Ответ 12

На основании некоторых других ответов, но этот будет отклонять программы с незаконными бинарными литералами. Ведущие нули являются необязательными.

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

Пример:

#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;
}

Ответ 13

Вы также можете использовать встроенную сборку следующим образом:

int i;

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

std::cout << i;

Хорошо, это может быть несколько излишним, но это работает.

Ответ 14

"Тип" двоичного числа совпадает с любым десятичным, шестнадцатеричным или восьмеричным числом: int (или даже char, короткий, длинный).

Когда вы назначаете константу, вы не можете назначить ее 11011011 (любопытно и, к сожалению), но вы можете использовать hex. Hex немного легче мысленно перевести. Chunk in nibbles (4 бит) и перевести на символ в [0-9a-f].

Ответ 15

Вы можете использовать битовый набор

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

Ответ 16

Я продлил хороший ответ, данный @renato-chandelier, обеспечив поддержку:

  • _NIBBLE_(…) - 4 бит, 1 nibble в качестве аргумента
  • _BYTE_(…) - 8 бит, 2 nibbles в качестве аргументов
  • _SLAB_(…) - 12 бит, 3 глыбы в качестве аргументов
  • _WORD_(…) - 16 бит, 4 глыбы в качестве аргументов
  • _QUINTIBBLE_(…) - 20 бит, 5 кусков в качестве аргументов
  • _DSLAB_(…) - 24 бит, 6 кусков в качестве аргументов
  • _SEPTIBBLE_(…) - 28 бит, 7 глаголов в качестве аргументов
  • _DWORD_(…) - 32 бита, 8 глаголов в качестве аргументов

Я действительно не так уверен в терминах "quintibble" и "septibble". Если кто-нибудь знает какую-либо альтернативу, пожалуйста, дайте мне знать.

Вот макрос, переписанный:

#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))

И вот пример Ренато:

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; */

Ответ 17

Просто используйте стандартную библиотеку в C++:

#include <bitset>

Вам нужна переменная типа std::bitset:

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

В этом примере я сохранил двоичную форму 10 в x.

8ul определяет размер ваших битов, поэтому 7ul означает семь битов и так далее.

Ответ 18

C++ предоставляет стандартный шаблон с именем std::bitset. Попробуйте, если хотите.

Ответ 19

Вы можете попробовать использовать массив bool:

bool i[8] = {0,0,1,1,0,1,0,1}