Можно ли использовать бинарный литерал в 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 для интересного обсуждения.
Ответ 2
Если вы используете GCC, вы можете использовать расширение GCC (которое включено в стандарт С++ 14):
int x = 0b00010000;
Ответ 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}