gpt4 book ai didi

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

转载 作者:可可西里 更新时间:2023-11-01 18:42:01 25 4
gpt4 key购买 nike

我有一组位标志,用于我从 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

...现在我了解到常量的#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_4DIMS = 2,
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++ 不支持类似于“0x”的“0b”值标志?
2. 定义标志的最佳样式是什么...
i. 命名空间封装常量。
ii. 命名空间包装了直接分配的无符号整数的枚举。
iii. 命名空间包装了使用可读二进制字符串分配的无符号整数枚举。

提前致谢!并且请不要因为主观性而关闭此线程,因为我真的很想获得关于什么是最好的风格以及为什么 c++ 缺乏内置二进制赋值功能的帮助。


编辑 1

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

最佳答案

在 C++14 之前,多年来一直在断断续续地讨论二进制文字,但据我所知,从来没有人写过一份严肃的提案来将它纳入标准,所以它从未真正通过谈论它的阶段。

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

在 C++11 中,他们没有直接添加二进制文字,而是添加了一种更通用的机制来允许通用的用户定义文字,您可以使用它来支持二进制、base 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)
};

关于c++ - 为什么 C++ 支持十六进制赋值,但不支持二进制赋值?如何最好地存储标志?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3834336/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com