У меня есть набор битовых флагов, которые используются в программе, которую я портирую с 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 ++ не поддерживает присваивание двоичного текста целочисленному типу, как, например, это позволяет назначать шестнадцатеричные числа таким образом (через «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.
Я подумываю использовать макро-решение Тома Торфа:
#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. Какой стиль определения флагов является наилучшим ...
i. Константы в пространстве имен.
ii. Перечисленное в пространстве имен перечисление неподписанных целых чисел, назначенных напрямую.
iii. Перечисленное в пространстве имен перечисление неподписанных целых чисел, назначаемых с помощью читаемой двоичной строки.
Заранее спасибо!И, пожалуйста, не закрывайте эту тему как субъективную, потому что я действительно хочу получить справку о том, что такое лучший стиль и почему в c ++ отсутствует встроенная возможность двоичного назначения.
РЕДАКТИРОВАТЬ 1
Немного дополнительной информации.Я буду читать 32-битное битовое поле из файла, а затем проверять его с этими флагами.Так что имейте это в виду при публикации предложений.