开始…
我程序中的标志以前定义为:
/* Define feature flags for this DCD file */ #define DCD_IS_CHARMM 0x01 #define DCD_HAS_4DIMS 0x02 #define DCD_HAS_EXTRA_BLOCK 0x04
…现在我已经收集了常量的#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; };
我们称这个想法为1.
我的另一个想法是使用整数枚举:
namespace DCD { enum e_Feature_Flags { IS_CHARMM = 1,HAS_4DIMS = 2,HAS_EXTRA_BLOCK = 8 }; };
但令我困扰的一件事是,当涉及到更高的价值时,它似乎不那么直观……
namespace DCD { enum e_Feature_Flags { IS_CHARMM = 1,HAS_EXTRA_BLOCK = 8,NEW_FLAG = 16,NEW_FLAG_2 = 32,NEW_FLAG_3 = 64,NEW_FLAG_4 = 128 }; };
我们称之为方法选项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 ) )
转换为内联函数,例如
#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") }; };
这疯了吗?还是看起来更直观?我们称之为选择3.
所以回顾一下,我的主要问题是:
1.为什么c不支持“0b”值标志,类似于“0x”?
2.哪种是定义标志的最佳方式……
一世.命名空间包装常量.
II.命名空间包含直接分配的无符号整数枚举.
III.命名空间包含使用可读二进制字符串分配的无符号整数的枚举.
提前致谢!请不要将此主题视为主观,因为我真的希望得到最佳风格的帮助,以及为什么c缺乏内置的二进制赋值功能.
编辑1
一些额外的信息.我将从一个文件中读取一个32位的位域,然后用这些标志进行测试.因此,当您发布建议时请记住这一点.
解决方法
对于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 }; };
另一种可能性是:
#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) };