Могу ли я использовать двоичный литерал в C или c++?



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



Я пыталась написать:



const x = 00010000;


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



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

856   19  

19 ответов:

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

обновление

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

к сожалению, вы не можете сделать базовое форматирование 2 с потоками STL (так как setbase будут чтить только базы 8, 10 и 16), но вы можете использовать std::string версия itoa, или (более кратким, но незначительно менее эффективным) std::bitset.

(спасибо Роджер на 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

также читайте Херба Саттера строка форматирования из фермерской усадьбы для интересного обсуждения.

Если вы используете GCC, то вы можете использовать расширение GCC (входит в стандарт C++14) для этого:

int x = 0b00010000;
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, но тем не менее.

вы можете использовать двоичные литералы. Они стандартизированы в C++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 теперь распознается либо как функция C++14, либо как расширение (см. разница между двоичным GCC литералы и C++14 из них?)

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

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

несколько компиляторов (обычно те, для микроконтроллеры) имеет специальную функцию, реализованную в распознавании буквенных двоичных чисел с помощью префикс " 0b..." предшествующий номер, хотя большинство компиляторов (стандарты C / 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" компиляторы и 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 тоже);

этой теме может помочь.

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

это работает! (Все кредиты идут тому торфу.)

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

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

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

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

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

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

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

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

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

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.

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

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

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

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

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

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

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

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

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

int i;

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

std::cout << i;

ладно, это может быть несколько излишне, но это работает :)

вы можете использовать bitset

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

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

  • _NIBBLE_(…) - 4 бита, 1 грызть в качестве аргумента
  • _BYTE_(…) - 8 бит, 2 грызет как аргументы
  • _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; */

просто используйте стандартную библиотеку в 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 означает семь бит и так далее.

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

вы можете попробовать:

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

Comments

    Ничего не найдено.