Двоичные литералы? - PullRequest
       57

Двоичные литералы?

47 голосов
/ 11 февраля 2009

В коде я иногда вижу, как люди указывают константы в шестнадцатеричном формате, например:

const int has_nukes        = 0x0001;
const int has_bio_weapons  = 0x0002;
const int has_chem_weapons = 0x0004;
// ...
int arsenal = has_nukes | has_bio_weapons | has_chem_weapons; // all of them
if(arsenal &= has_bio_weapons){
  std::cout << "BIO!!"
}

Но мне не имеет смысла использовать здесь шестнадцатеричный формат. Есть ли способ сделать это непосредственно в двоичном коде? Примерно так:

const int has_nukes        = 0b00000000000000000000000000000001;
const int has_bio_weapons  = 0b00000000000000000000000000000010;
const int has_chem_weapons = 0b00000000000000000000000000000100;
// ...

Я знаю, что компиляторы C / C ++ не скомпилируют это, но должен быть обходной путь? Возможно ли это на других языках, таких как Java?

Ответы [ 17 ]

63 голосов
/ 09 сентября 2013

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

0b010101010 /* more zeros and ones */

Эта функция уже реализована в последних clang и gcc. Вы можете попробовать это, если вы запустите эти компиляторы с опцией -std=c++1y.

61 голосов
/ 11 февраля 2009

Я бы использовал оператор сдвига битов:

const int has_nukes        = 1<<0;
const int has_bio_weapons  = 1<<1;
const int has_chem_weapons = 1<<2;
// ...
int dangerous_mask = has_nukes | has_bio_weapons | has_chem_weapons;
bool is_dangerous = (country->flags & dangerous_mask) == dangerous_mask;

Это даже лучше, чем поток 0.

34 голосов
/ 11 февраля 2009

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

template<char... digits>
constexpr int operator "" _b() {
    return conv2bin<digits...>::value;
}

int main() {
    int const v = 110110110_b;
}

conv2bin будет такой шаблон:

template<char... digits>
struct conv2bin;

template<char high, char... digits>
struct conv2bin<high, digits...> {
    static_assert(high == '0' || high == '1', "no bin num!");
    static int const value = (high - '0') * (1 << sizeof...(digits)) + 
                             conv2bin<digits...>::value;
};

template<char high>
struct conv2bin<high> {
    static_assert(high == '0' || high == '1', "no bin num!");
    static int const value = (high - '0');
};

Что ж, мы получаем двоичные литералы, которые полностью оценивают уже во время компиляции, из-за "constexpr" выше. Выше используется жестко закодированный тип возврата int. Я думаю, что можно даже сделать это зависит от длины двоичной строки. Для тех, кто заинтересован, используются следующие функции:

На самом деле, текущая магистраль GCC уже реализует шаблоны переменных и статические утверждения. Будем надеяться, что это скоро поддержит двух других. Я думаю, что C ++ 1x раскачивает дом.

15 голосов
/ 11 февраля 2009

Стандартная библиотека C ++ - ваш друг:

#include <bitset>

const std::bitset <32> has_nukes( "00000000000000000000000000000001" );
13 голосов
/ 11 февраля 2009

Вы можете использовать <<, если хотите. </p>

int hasNukes = 1;
int hasBioWeapons = 1 << 1;
int hasChemWeapons = 1 << 2;
12 голосов
/ 11 февраля 2009

GCC поддерживает двоичные константы как расширение начиная с 4.3. См. Объявление (см. Раздел «Новые языки и улучшения для конкретных языков»).

9 голосов
/ 11 февраля 2009

Вы хотите использовать термин двоичные литералы

В Ruby они есть с указанным вами синтаксисом.

Одной из альтернатив является определение вспомогательных макросов для преобразования для вас. Я нашел следующий код на http://bytes.com/groups/c/219656-literal-binary

/* Binary constant generator macro
 * By Tom Torfs - donated to the public domain
 */

/* All macro's evaluate to compile-time constants */

/* *** helper macros *** */

/* turn a numeric literal into a hex constant
 * (avoids problems with leading zeroes)
 * 8-bit constants max value 0x11111111, always fits in unsigned long
 */
#define HEX_(n) 0x##n##LU

/* 8-bit conversion function */
#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 *** /

/* for upto 8-bit binary constants */
#define B8(d) ((unsigned char) B8_(HEX_(d)))

/* for upto 16-bit binary constants, MSB first */
#define B16(dmsb, dlsb) (((unsigned short) B8(dmsb) << 8) \
                                         | B8(dlsb))

/* for upto 32-bit binary constants, MSB first */
#define B32(dmsb, db2, db3, dlsb) (((unsigned long) B8(dmsb) << 24) \
                                 | ((unsigned long) B8( db2) << 16) \
                                 | ((unsigned long) B8( db3) <<  8) \
                                 |                  B8(dlsb))

/* Sample usage:
 * B8(01010101) = 85
 * B16(10101010,01010101) = 43605
 * B32(10000000,11111111,10101010,01010101) = 2164238933
 */
9 голосов
/ 11 февраля 2009

Это обсуждение может быть интересным ... Возможно, так как ссылка к сожалению не работает. Здесь описан подход на основе шаблонов, аналогичный другим ответам здесь.

А также есть вещь, которая называется BOOST_BINARY .

4 голосов
/ 11 февраля 2009

Я пишу двоичные литералы так:

const int has_nukes        = 0x0001;
const int has_bio_weapons  = 0x0002;
const int has_chem_weapons = 0x0004;

Он более компактен, чем вы предлагаете, и его легче читать. Например:

const int upper_bit = 0b0001000000000000000;

против

const int upper_bit = 0x04000;

Вы заметили, что двоичная версия не была даже кратна 4 битам? Вы думали, что это был 0x10000?

С небольшой практикой шестнадцатеричное или восьмеричное легче для человека, чем двоичное. И, на мой взгляд, легче читать, используя операторы сдвига. Но я признаю, что мои годы работы на ассемблере могут меня сместить в этом вопросе.

4 голосов
/ 11 февраля 2009

Следующая версия C ++, C ++ 0x, представит пользовательские литералы . Я не уверен, будут ли двоичные числа частью стандарта, но в худшем случае вы сможете включить его самостоятельно:

int operator "" _B(int i);

assert( 1010_B == 10);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...