为什么C++支持十六进制赋值,但是缺少二进制赋值?如何最好地存储标志?

Jas*_*ick 6 c++ binary flags inline variable-assignment

我有一组位标志,用于我从C到C++移植的程序.

开始...

我程序中的标志以前定义为:

/* Define feature flags for this DCD file */
#define DCD_IS_CHARMM       0x01
#define DCD_HAS_4DIMS       0x02
#define DCD_HAS_EXTRA_BLOCK 0x04
Run Code Online (Sandbox Code Playgroud)

...现在我已经收集了常量的#defines(与类常量等相比)通常被认为是不好的形式.

这引发了关于如何最好地在c ++中存储位标志以及为什么c ++不支持将二进制文本分配给int的问题,就像它允许以这种方式分配十六进制数字(通过"0x").这篇问题总结在本文末尾.

我可以看到一个简单的解决方案是简单地创建单个常量:

namespace DCD {
   const unsigned int IS_CHARMM = 1;
   const unsigned int HAS_4DIMS = 2;
   const unsigned int HAS_EXTRA_BLOCK = 4;
};
Run Code Online (Sandbox Code Playgroud)

我们称这个想法为1.

我的另一个想法是使用整数枚举:

namespace DCD {
   enum e_Feature_Flags {
      IS_CHARMM = 1,
      HAS_4DIMS = 2,
      HAS_EXTRA_BLOCK = 8
   };
};
Run Code Online (Sandbox Code Playgroud)

但令我困扰的一件事是,当涉及更高的价值时,它似乎不那么直观......似乎......

namespace DCD {
   enum e_Feature_Flags {
      IS_CHARMM = 1,
      HAS_4DIMS = 2,
      HAS_EXTRA_BLOCK = 8,
      NEW_FLAG = 16,
      NEW_FLAG_2 = 32,
      NEW_FLAG_3 = 64,
      NEW_FLAG_4 = 128
   };
};
Run Code Online (Sandbox Code Playgroud)

我们称之为方法选项2.

我正在考虑使用Tom Torf的宏解决方案:

#define B8(x) ((int) B8_(0x##x))

#define B8_(x) \
( ((x) & 0xF0000000) >( 28 - 7 ) \
| ((x) & 0x0F000000) >( 24 - 6 ) \
| ((x) & 0x00F00000) >( 20 - 5 ) \
| ((x) & 0x000F0000) >( 16 - 4 ) \
| ((x) & 0x0000F000) >( 12 - 3 ) \
| ((x) & 0x00000F00) >( 8 - 2 ) \
| ((x) & 0x000000F0) >( 4 - 1 ) \
| ((x) & 0x0000000F) >( 0 - 0 ) )
Run Code Online (Sandbox Code Playgroud)

转换为内联函数,例如

#include <iostream>
#include <string>
....

/* TAKEN FROM THE C++ LITE FAQ [39.2]... */
class BadConversion : public std::runtime_error {
 public:
   BadConversion(std::string const& s)
     : std::runtime_error(s)
     { }
};

inline double convertToUI(std::string const& s)
{
   std::istringstream i(s);
   unsigned int x;
   if (!(i >> x))
     throw BadConversion("convertToUI(\"" + s + "\")");
   return x;
} 
/** END CODE **/

inline unsigned int B8(std::string x) {
   unsigned int my_val = convertToUI(x.insert(0,"0x").c_str());
   return ((my_val) & 0xF0000000) >( 28 - 7 ) |
            ((my_val) & 0x0F000000) >( 24 - 6 ) | 
            ((my_val) & 0x00F00000) >( 20 - 5 ) |
            ((my_val) & 0x000F0000) >( 16 - 4 ) |
            ((my_val) & 0x0000F000) >( 12 - 3 ) |
            ((my_val) & 0x00000F00) >( 8 - 2 ) |
            ((my_val) & 0x000000F0) >( 4 - 1 ) |
            ((my_val) & 0x0000000F) >( 0 - 0 );
}

namespace DCD {
   enum e_Feature_Flags {
      IS_CHARMM       = B8("00000001"),
      HAS_4DIMS       = B8("00000010"),
      HAS_EXTRA_BLOCK = B8("00000100"),
      NEW_FLAG        = B8("00001000"),
      NEW_FLAG_2      = B8("00010000"),
      NEW_FLAG_3      = B8("00100000"),
      NEW_FLAG_4      = B8("01000000")
   };
};
Run Code Online (Sandbox Code Playgroud)

这疯了吗?还是看起来更直观?我们称之为选择3.

所以回顾一下,我的主要问题是:

1. 为什么c ++不支持"0b"值标志,类似于"0x"?
2. 定义标志的最佳方式是哪种...
i. 命名空间包装常量.
II. 命名空间包含直接分配的无符号整数枚举.
III.命名空间包含使用可读二进制字符串分配的无符号整数的枚举.

提前致谢!请不要将此主题视为主观,因为我真的希望得到最好的风格以及为什么c ++缺乏内置的二进制赋值功能.


编辑1

一些额外的信息.我将从一个文件中读取一个32位的位域,然后用这些标志进行测试.因此,当您发布建议时请记住这一点.

Jer*_*fin 13

在C++ 14之前,多年来一直在讨论二进制文字,但据我所知,没有人曾经写过一个认真的提议来达到标准,所以它从未真正超越了谈论它.

对于C++ 14,有人最终写了一个提案,并且委员会接受了它,所以如果你可以使用当前的编译器,那么问题的基本前提是错误的 - 你可以使用具有该形式的二进制文字0b01010101.

在C++ 11中,它们不是直接添加二进制文字,而是添加了一种更通用的机制来允许一般的用户定义文字,您可以使用它来完全支持二进制或基本64或其他类型的文本.基本思想是指定一个数字(或字符串)文字后跟一个后缀,你可以定义一个接收该文字的函数,并将其转换为你喜欢的任何形式(并且你可以将其状态保持为"常量") "太......)

至于使用哪个:如果可以的话,C++ 14或更高版本中内置的二进制文字是显而易见的选择.如果你不能使用它们,我通常更喜欢选项2的变体:带有初始化器的枚举为十六进制:

namespace DCD {
   enum e_Feature_Flags {
      IS_CHARMM = 0x1,
      HAS_4DIMS = 0x2,
      HAS_EXTRA_BLOCK = 0x8,
      NEW_FLAG = 0x10,
      NEW_FLAG_2 = 0x20,
      NEW_FLAG_3 = 0x40,
      NEW_FLAG_4 = 0x80
   };
};
Run Code Online (Sandbox Code Playgroud)

另一种可能性是:

#define bit(n) (1<<(n))

enum e_feature_flags = { 
    IS_CHARM = bit(0), 
    HAS_4DIMS = bit(1),
    HAS_EXTRA_BLOCK = bit(3),
    NEW_FLAG = bit(4),
    NEW_FLAG_2 = bit(5),
    NEW_FLAG_3 = bit(6),
    NEW_FLAG_4 = bit(7)
};
Run Code Online (Sandbox Code Playgroud)


Jam*_*lis 7

使用选项二,您可以使用左移,这可能不那么"不直观":

namespace DCD { 
   enum e_Feature_Flags { 
      IS_CHARMM =        1, 
      HAS_4DIMS =       (1 << 1), 
      HAS_EXTRA_BLOCK = (1 << 2), 
      NEW_FLAG =        (1 << 3), 
      NEW_FLAG_2 =      (1 << 4), 
      NEW_FLAG_3 =      (1 << 5), 
      NEW_FLAG_4 =      (1 << 6) 
   }; 
};
Run Code Online (Sandbox Code Playgroud)