C++ 二进制常量/文字

发布于 2024-07-16 07:03:23 字数 364 浏览 2 评论 0原文

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

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

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

因此您可以执行类似“binary<101011011>::value”的操作。 不幸的是,无符号 long long 的长度限制为 20 位。

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

I'm using a well known template to allow 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 } ;
};

So you can do something like binary<101011011>::value. Unfortunately this has a limit of 20 digits for a unsigned long long.

Does anyone have a better solution?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

大海や 2024-07-23 07:03:23

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

这导致了一种从该解决方案中挤出更多数字的方法 - 始终以零开始二进制常量! 然后将模板中的 10 替换为 8。

Does this work if you have a leading zero on your binary value? A leading zero makes the constant octal rather than decimal.

Which leads to a way to squeeze a couple more digits out of this solution - always start your binary constant with a zero! Then replace the 10's in your template with 8's.

薯片软お妹 2024-07-23 07:03:23

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

1/只使用十六进制。 一段时间后,您就会知道哪些十六进制数字代表哪些位模式。

2/ 使用常量并对它们进行“或”或“加”操作。 例如(可能需要对位模式进行限定符以使它们成为无符号或长整型):

#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”常量,但这可能有点矫枉过正:-)

The approaches I've always used, though not as elegant as yours:

1/ Just use hex. After a while, you just get to know which hex digits represent which bit patterns.

2/ Use constants and OR or ADD them. For example (may need qualifiers on the bit patterns to make them unsigned or long):

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

unsigned long x = b2 | b7

3/ If performance isn't critical and readability is important, you can just do it at runtime with a function such as "x = fromBin("101011011");".

4/ As a sneaky solution, you could write a pre-pre-processor that goes through your *.cppme files and creates the *.cpp ones by replacing all "0b101011011"-type strings with their equivalent "0x15b" strings). I wouldn't do this lightly since there's all sorts of tricky combinations of syntax you may have to worry about. But it would allow you to write your string as you want to without having to worry about the vagaries of the compiler, and you could limit the syntax trickiness by careful coding.

Of course, the next step after that would be patching GCC to recognize "0b" constants but that may be an overkill :-)

弥繁 2024-07-23 07:03:23

C++0x 有 用户定义的文字,可用于实现您正在谈论的内容。

不然我不知道如何改进这个模板。

C++0x has user-defined literals, which could be used to implement what you're talking about.

Otherwise, I don't know how to improve this template.

我们只是彼此的过ke 2024-07-23 07:03:23
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::value

更加详细,但没有限制(当然,直到达到 unsigned int 的大小)。

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

Allowing:

Bin::O::I::I::O::O::value

much more verbose, but no limits (until you hit the size of an unsigned int of course).

Hello爱情风 2024-07-23 07:03:23

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

// 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 开头会导致被解释为八进制数的数字。)

You can add more non-type template parameters to "simulate" additional bits:

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

You can use this as before, e.g.:

binary<1001101>::value

But you can also use the following equivalent forms:

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

Basically, the extra parameter gives you another 20 bits to play with. You could add even more parameters if necessary.

Because the place value of the second number is used to figure out how far to the left the first number needs to be shifted, the second number must begin with a 1. (This is required anyway, since starting it with a 0 would cause the number to be interpreted as an octal number.)

一人独醉 2024-07-23 07:03:23

从技术上讲,它不是 C 也不是 C++,它是 GCC 特定的扩展,但 GCC 允许 二进制常量此处所示:

 The following statements are identical:

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

希望有所帮助。 一些 Intel 编译器(我相信还有其他编译器)实现了一些 GNU 扩展。 也许你很幸运。

Technically it is not C nor C++, it is a GCC specific extension, but GCC allows binary constants as seen here:

 The following statements are identical:

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

Hope that helps. Some Intel compilers and I am sure others, implement some of the GNU extensions. Maybe you are lucky.

避讳 2024-07-23 07:03:23

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

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

A simple #define works very well:

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

Not my invention, I saw it on a forum a long time ago.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文