我正在使用一个众所周知的模板来允许二进制常量
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个数字的限制。
有没有人有更好的解决方案?
答案 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)
不是我的发明,我很久以前就在论坛上看到了它。