C ++二进制常量/文字

时间:2009-03-31 02:16:56

标签: c++ templates binary constants

我正在使用一个众所周知的模板来允许二进制常量

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

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

所以你可以做二进制&lt; 101011011&gt; :: value。不幸的是,对于无符号长的长度,它有20个数字的限制。

有没有人有更好的解决方案?

7 个答案:

答案 0 :(得分:25)

如果你的二进制值有一个前导零,这是否有效?前导零使得常数八进制而不是十进制。

这导致了一种从这个解决方案中挤出更多数字的方法 - 总是以零开始你的二进制常量!然后用8's替换模板中的10个。

答案 1 :(得分:5)

我一直使用的方法,虽然不如你的优雅:

1 /只需使用十六进制。过了一会儿,你就会知道哪些十六进制数字代表哪些位模式。

2 /使用常数和OR或添加它们。例如(可能需要对位模式使用限定符以使它们无符号或长):

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

unsigned long x = b2 | b7

3 /如果性能不重要且可读性很重要,您可以在运行时使用诸如“x = fromBin(”101011011“);”。

之类的功能来执行此操作。

4 /作为一个偷偷摸摸的解决方案,您可以编写一个预处理器来处理您的* .cppme文件并通过将所有“0b101011011”类型的字符串替换为其等效的“0x15b”字符串来创建* .cpp文件)。我不会轻易做到这一点,因为你可能不得不担心各种棘手的语法组合。但是它允许你根据需要编写字符串,而不必担心编译器的变化,你可以通过仔细编码来限制语法的诡计。

当然,之后的下一步是修补GCC以识别“0b”常量,但这可能是一种过度杀伤: - )

答案 2 :(得分:4)

C ++ 0x有user-defined literals,可用于实现您所说的内容。

否则,我不知道如何改进此模板。

答案 3 :(得分:3)

您可以添加更多非类型模板参数来“模拟”其他位:

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

您可以像以前一样使用它,例如:

binary<1001101>::value

但您也可以使用以下等效形式:

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

基本上,额外的参数可以让你再玩20位。如有必要,您可以添加更多参数。

因为第二个数字的位置值用于计算左边第一个数字需要移位的距离,所以第二个数字必须以1开头。(无论如何,这是必需的,因为它以0开始)会导致数字被解释为八进制数。)

答案 4 :(得分:3)

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

允许:

宾::ö::我::我::ö::Ò::值

更冗长,但没有限制(当然你要达到无符号整数的大小)。

答案 5 :(得分:3)

从技术上讲,它不是C和C ++,它是GCC特定的扩展,但是GCC允许binary constants看到here

 The following statements are identical:

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

希望有所帮助。一些英特尔编译器,我相信其他人,实现了一些GNU扩展。也许你很幸运。

答案 6 :(得分:2)

简单的#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)

不是我的发明,我很久以前就在论坛上看到了它。