Почему обычно перечисляются флаги с шестнадцатеричными значениями

Много раз я вижу объявления перечисления флага, которые используют шестнадцатеричные значения. Например:

[Flags]
public enum MyEnum
{
    None  = 0x0,
    Flag1 = 0x1,
    Flag2 = 0x2,
    Flag3 = 0x4,
    Flag4 = 0x8,
    Flag5 = 0x10
}

Когда я объявляю перечисление, я обычно объявляю его следующим образом:

[Flags]
public enum MyEnum
{
    None  = 0,
    Flag1 = 1,
    Flag2 = 2,
    Flag3 = 4,
    Flag4 = 8,
    Flag5 = 16
}

Есть ли причина или обоснование того, почему некоторые люди предпочитают писать значение в шестнадцатеричном, а не в десятичном формате? То, как я это вижу, легче запутаться при использовании шестнадцатеричных значений и случайно записать Flag5 = 0x16 вместо Flag5 = 0x10.

Ответ 1

Обоснования могут отличаться, но я вижу, что шестнадцатиричное напоминание: "Хорошо, мы больше не имеем дело с числами в произвольном человеческом мире, основанном на базе 10. Мы имеем дело с битами - мир машины - и мы будем играть по своим правилам". Шестнадцатеричный редко используется, если вы не имеете дело с относительно низкоуровневыми темами, где важна структура памяти данных. Использование этого намека на тот факт, что ситуация, в которой мы сейчас находимся.

Кроме того, я не уверен в С#, но я знаю, что в C x << y допустимая константа компиляции. Использование бит-сдвигов кажется наиболее ясным:

[Flags]
public enum MyEnum
{
    None  = 0,
    Flag1 = 1 << 0,
    Flag2 = 1 << 1,
    Flag3 = 1 << 2,
    Flag4 = 1 << 3,
    Flag5 = 1 << 4
}

Ответ 2

Легко видеть, что это двоичные флаги.

None  = 0x0,  // == 00000
Flag1 = 0x1,  // == 00001
Flag2 = 0x2,  // == 00010
Flag3 = 0x4,  // == 00100
Flag4 = 0x8,  // == 01000
Flag5 = 0x10  // == 10000

Хотя прогрессия делает его еще более ясным:

Flag6 = 0x20  // == 00100000
Flag7 = 0x40  // == 01000000
Flag8 = 0x80  // == 10000000

Ответ 3

Я думаю, это просто потому, что последовательность всегда равна 1,2,4,8, а затем добавляет 0.
Как вы можете видеть:

0x1 = 1 
0x2 = 2
0x4 = 4
0x8 = 8
0x10 = 16
0x20 = 32
0x40 = 64
0x80 = 128
0x100 = 256
0x200 = 512
0x400 = 1024
0x800 = 2048

и т.д., пока вы помните последовательность 1-2-4-8, вы можете построить все последующие флаги без необходимости запоминать полномочия 2

Ответ 4

Потому что [Flags] означает, что перечисление действительно является битовым полем. С помощью [Flags] вы можете использовать побитовые операторы AND (&) и OR (|) для объединения флагов. При использовании двоичных значений, подобных этому, почти всегда более понятно использовать шестнадцатеричные значения. Именно по этой причине мы используем шестнадцатеричный. Каждый шестнадцатеричный символ соответствует ровно одному полубайту (четыре бита). С десятичной точностью это сопоставление 1-to-4 не выполняется.

Ответ 5

Потому что есть механический, простой способ удвоить мощность в два в гексагоне. В десятичной системе это сложно. Это требует длительного размножения в голове. В шестнадцатеричном виде это простое изменение. Вы можете выполнить все это до 1UL << 63, которое вы не можете сделать в десятичном формате.

Ответ 6

Потому что легче следить за людьми, где бит находится в флагове. Каждая шестнадцатеричная цифра может соответствовать 4-битовому двоичному файлу.

0x0 = 0000
0x1 = 0001
0x2 = 0010
0x3 = 0011

... and so on

0xF = 1111

Обычно вы хотите, чтобы ваши флаги не перекрывали биты, самый простой способ сделать это и визуализировать его - использовать шестнадцатеричные значения для объявления ваших флагов.

Итак, если вам нужны флаги с 16 битами, вы будете использовать четырехзначные шестнадцатеричные значения и таким образом вы можете избежать ошибочных значений:

0x0001 //= 1 = 000000000000 0001
0x0002 //= 2 = 000000000000 0010
0x0004 //= 4 = 000000000000 0100
0x0008 //= 8 = 000000000000 1000
...
0x0010 //= 16 = 0000 0000 0001 0000
0x0020 //= 32 = 0000 0000 0010 0000
...
0x8000 //= 32768 = 1000 0000 0000 0000