Могу ли я использовать двоичный литерал в C или C ++? - PullRequest
177 голосов
/ 10 апреля 2010

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

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

const x = 00010000;

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

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

Ответы [ 19 ]

247 голосов
/ 10 апреля 2010

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

int x = 0b00010000;
77 голосов
/ 07 апреля 2015

Вы можете использовать двоичные литералы. Они стандартизированы в 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 Preview (см. https://www.visualstudio.com/news/vs2015-preview-vs#C++).

73 голосов
/ 10 апреля 2010
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, но тем не менее.

67 голосов
/ 10 апреля 2010

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

UPDATE

Чтобы сделать обратное (то есть распечатать число в двоичной форме), вы можете использовать непереносимую 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

Также прочитайте интересную дискуссию Херба Саттера Строковые расширители усадебной фермы .

30 голосов
/ 28 сентября 2011

Несколько компиляторов (обычно для микроконтроллеров ) имеют специальную функцию, реализованную в распознавании буквенных двоичных чисел по префиксу "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);
  • Имеет только ограничение "longness" для выражения значений "literal constant". Было бы раннее ограничение длинны (обычно 8 битов: 0-255), если бы кто-либо выражал постоянные значения путем анализа разрешения "enum solution" (usually 255 = reach enum definition limit), иначе, ограничения «буквальной константы» в компиляторе допускают большие числа;
  • Некоторые другие решения требуют преувеличенного числа определений констант (на мой взгляд, слишком много определений), включая long или several header files (в большинстве случаев не легко читаемые и понятные, и делают проект излишне запутанным и расширенным, например, используя "BOOST_BINARY()");
  • Простота решения: легко читаемый, понятный и настраиваемый для других случаев (может быть расширен для групп 8 на 8);
20 голосов
/ 10 апреля 2010

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

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

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

15 голосов
/ 10 апреля 2010

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

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

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

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

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

14 голосов
/ 07 ноября 2013

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

unsigned char x = 0xF; // binary: 00001111
12 голосов
/ 10 апреля 2010

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

9 голосов
/ 10 апреля 2010

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...