Я пытаюсь преобразовать перечисление из кода C ++ в код C #, и у меня возникают проблемы, когда я оборачиваюсь вокруг него. Код C ++:
enum FOO {
FOO_1 = 0,
FOO_2,
// etc
}
#define MASK(x) ((1 << 16) | (x))
enum DISP
{
DISP_1 = MASK(FOO_1),
DISP_2 = MASK(FOO_2),
// etc
}
Что я не понимаю, так это то, что делает MASK, и как я могу либо эмулировать функциональность в C #, либо понять, что он делает, и установить enum DISP вручную без него.
Я не уверен, что то, что я говорю, имеет смысл, но этого следует ожидать, когда я не совсем уверен, на что я смотрю.
MASK(x)
строит число по OR
в ряд x
с двоичным числом 10000000000000000
(один сдвинут влево 16 раз).
В C # вы можете использовать выражение напрямую, например так:
enum FOO {
FOO_1 = 0,
FOO_2,
// etc
}
enum DISP
{
DISP_1 = (1<<16) | (int)(FOO.FOO_1),
DISP_2 = (1<<16) | (int)(FOO.FOO_2),
// etc
}
когда вы сдвигаете бит, он сдвигает все 1 и 0 влево или вправо на некоторое количество значений.
в твоем случае 1 << 16
создает 10000000000000000 в двоичном формате. (да, это 16 нулей).
Затем он берет это число и использует |
который является побитовым или оператором. таким образом, каким бы ни было целочисленное значение перечисления, оно разбито по битам на то число, которое мы сдвинули.
Если, например, вы используете MASK(FOO_4)
(который имеет буквальное значение 3) 3 равно 11 в двоичном формате, поэтому результат будет 10000000000000011. Это функционально аналогично добавлению 65 536 к каждому значению.
Теперь, когда мы объявляем второе перечисление, мы устанавливаем значения этих значений перечисления для этой странной маскирующей функции.
Чтобы сделать то же самое в C # попробуйте это:
enum Foo { //this may not be needed anymore?
FOO_1 = 0, FOO_2, ... etc
}
enum Disp { //DISP_2 gets the next value ie 65536 + 1, and so forth
DISP_1 = 65536, DISP_2, DISP_3, ... etc
Просто замени MASK
с тем, что это определено как ( <<
а также |
операторы существуют и в C #):
enum DISP
{
DISP_1 = ((1 << 16) | FOO.FOO_1),
DISP_2 = ((1 << 16) | FOO.FOO_2)
}
Если вам интересно, что именно выполняют операторы shift или or, вы принимаете двоичное значение 0000000000000001
и сдвигает его на 16 значений влево: 1000000000000000
,
Другой пример, (000001101 << 3)
становится 001101000
,
Оператор or берет все значения 1 из любого операнда и устанавливает значение результата в 1.
Например, 0001 | 0110
становится 0111
,
Итак, возьмите DISP_2:
(0b00000000000000001 << 16) | 0b00000000000000010)
= (0b10000000000000000 | 0b00000000000000010)
= (0b10000000000000010)
= 65538
(Я знаю 0b
формат не работает в C # и не является стандартным в C, но более полезно использовать двоичную нотацию вместо шестнадцатеричной, чтобы легче было видеть, что делают операторы)
Числовые значения, которые DISP_x равны:
DISP_1 == 0x10000
DISP_2 == 0x10001
DISP_3 == 0x10002
...
Оператор сдвига битов работает в C #, а макрос определения — нет.
Чтобы понять, что происходит, вы можете рассчитать значения отдельно и затем поместить их в перечисление.
Конечно, вы знаете, что |
является побитовым оператором ИЛИ. И на всякий случай какой оператор <<
делает сдвиг двоичного файла влево:
1 << 16 = 10000000000000000_2 //those are 16 zeroes and _2 indicates binary
В очереди:
10000000000000000_2 = 65536
Это является эквивалентом умножения числа на 2 количество раз, указанное вторым операндом.
1 << 1 = 2
1 << 2 = 4
1 << 3 = 8
Это верно, это умножение числа на степень двух:
1 << 1 <=> 1 * 2^1 = 2
1 << 2 <=> 1 * 2^2 = 4
1 << 3 <=> 1 * 2^3 = 8
Сейчас, с FOO_1 = 0
затем
DISP_1 = MASK(FOO_1)
=>
DISP_1 = ((1 << 16) | (FOO_1))
=>
DISP_1 = (65536 | (FOO_1))
=>
DISP_1 = (65536 | FOO_1)
=>
DISP_1 = (65536 | 0)
=>
DISP_1 = 65536
Делать то же самое для FOO_2
который я беру, имеет значение 1, которое даст вам:
DISP_2 = (65536 | FOO_2)
=>
DISP_2 = (65536 | 1)
=>
DISP_2 = 65537
При этом правильно работает следующее:
enum FOO
{
FOO_1 = 0,
FOO_2,
// etc
}
enum DISP
{
DISP_1 = (1<<16) | (int)(FOO.FOO_1),
DISP_2 = (1<<16) | (int)(FOO.FOO_2),
// etc
}