C ++ двоичная константа / литерал - PullRequest
13 голосов
/ 31 марта 2009

Я использую хорошо известный шаблон для разрешения двоичных констант

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

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

Так что вы можете сделать что-то вроде двоичного <101011011> :: value. К сожалению, для длинного длинного без знака это ограничение в 20 цифр.

У кого-нибудь есть лучшее решение?

Ответы [ 7 ]

25 голосов
/ 31 марта 2009

Это работает, если у вас есть начальный ноль в вашем двоичном значении? Ведущий ноль делает константу восьмеричной, а не десятичной.

Что приводит к способу выжать еще пару цифр из этого решения - всегда начинайте двоичную константу с нуля! Затем замените 10 в вашем шаблоне на 8.

5 голосов
/ 31 марта 2009

Подходы, которые я всегда использовал, хотя и не такие элегантные, как у вас:

1 / Просто используйте гекс. Через некоторое время вы просто узнаете, какие шестнадцатеричные цифры представляют какие битовые комбинации.

2 / Используйте константы и ИЛИ или ДОБАВЬТЕ их. Например (могут потребоваться квалификаторы на битовых шаблонах, чтобы сделать их беззнаковыми или длинными):

#define b0  0x00000001
#define b1  0x00000002
: : :
#define b31 0x80000000

unsigned long x = b2 | b7

3 / Если производительность не критична, а читабельность важна, вы можете просто сделать это во время выполнения с помощью функции, такой как "x = fromBin (" 101011011 ");".

4 / В качестве хитрого решения вы можете написать предварительный препроцессор, который просматривает ваши файлы * .cppme и создает файлы * .cpp, заменяя все строки типа «0b101011011» их эквивалентными строками «0x15b» ). Я бы не стал делать это легко, так как есть множество хитрых комбинаций синтаксиса, о которых вам, возможно, придется беспокоиться. Но это позволит вам писать свою строку так, как вы хотите, не беспокоясь о капризах компилятора, и вы можете ограничить хитрость синтаксиса путем тщательного кодирования.

Конечно, следующим шагом после этого будет исправление GCC для распознавания констант "0b", но это может быть излишним: -)

4 голосов
/ 31 марта 2009

C ++ 0x имеет пользовательских литералов , которые могут быть использованы для реализации того, о чем вы говорите.

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

3 голосов
/ 04 ноября 2009

Технически это не C и не C ++, это специфическое расширение GCC, но GCC допускает двоичные константы , как видно здесь :

 The following statements are identical:

 i =       42;
 i =     0x2a;
 i =      052;
 i = 0b101010;

Надеюсь, это поможет. Некоторые компиляторы Intel и, я уверен, другие, реализуют некоторые расширения GNU. Может быть, вам повезло.

3 голосов
/ 27 мая 2009
template<unsigned int p,unsigned int i> struct BinaryDigit 
{
  enum  { value = p*2+i };
  typedef BinaryDigit<value,0> O;
  typedef BinaryDigit<value,1> I;
};
struct Bin
{
  typedef BinaryDigit<0,0> O;
  typedef BinaryDigit<0,1> I;
};

Разрешение:

Bin :: O :: I :: I :: O :: O :: Значение

гораздо более многословно, но без ограничений (конечно, пока вы не достигнете размера без знака int).

3 голосов
/ 31 марта 2009

Вы можете добавить больше нетипизированных параметров шаблона для «имитации» дополнительных битов:

// Utility metafunction used by top_bit<N>.
template <unsigned long long N1, unsigned long long N2>
struct compare {
    enum { value = N1 > N2 ? N1 >> 1 : compare<N1 << 1, N2>::value };
};

// This is hit when N1 grows beyond the size representable
// in an unsigned long long.  It's value is never actually used.
template<unsigned long long N2>
struct compare<0, N2> {
    enum { value = 42 };
};

// Determine the highest 1-bit in an integer.  Returns 0 for N == 0.
template <unsigned long long N>
struct top_bit {
    enum { value = compare<1, N>::value };
};

template <unsigned long long N1, unsigned long long N2 = 0>
struct binary {
    enum {
        value =
            (top_bit<binary<N2>::value>::value << 1) * binary<N1>::value +
            binary<N2>::value
    };
};

template <unsigned long long N1>
struct binary<N1, 0> {
    enum { value = (N1 % 10) + 2 * binary<N1 / 10>::value };
};

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

Вы можете использовать это, как и раньше, например ::10000

binary<1001101>::value

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

binary<100,1101>::value
binary<1001,101>::value
binary<100110,1>::value

По сути, дополнительный параметр дает вам еще 20 бит для игры. При необходимости вы можете добавить еще больше параметров.

Поскольку значение места второго числа используется для определения того, как далеко влево должно быть смещено первое число, второе число должно начинаться с 1. (Это необходимо в любом случае, поскольку начинать его с 0 приведет к тому, что число будет интерпретировано как восьмеричное число.)

2 голосов
/ 04 ноября 2009

Простой #define работает очень хорошо:

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

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

B8(011100111)
B16(10011011,10011011)
B32(10011011,10011011,10011011,10011011)

Не мое изобретение, я видел его на форуме давным-давно.

...