Получить значение в функции с помощью битовых манипуляций

#c #bit-manipulation #bit

#c #битовые манипуляции #бит

Вопрос:

В конкретной графической библиотеке пиксели представлены 32-битными значениями, состоящими из четырех байтов для представления четырех компонентов: КРАСНОГО, ЗЕЛЕНОГО, СИНЕГО и альфа. Доступны следующие определения:

 typedef unsigned int Uint32;
typedef unsigned char byte;
enum Color { RED = 0, GREEN = 1, BLUE = 2, ALPHA = 3 };
  

Теперь нужны две свободные функции:

 Byte getColorComponent (Uint32 pixel, Color color);
  

которая посредством битовых манипуляций извлекает и возвращает значение одного из четырех цветовых компонентов, показанных в аргументе color;
и

 void setColorComponent (Uint32 amp; pixel, Byte value, Color color);
  

которая принимает остановки в байтовом значении в нужном месте (в соответствии с аргументом color) в пикселе.

Ответ таков:

 Byte getColorComponent(Uint32 pixel, Color color){   return (pixel >> (3-color)*8) amp; 0xFF; } 
void setColorComponent(Uint32amp; pixel, Byte value, Color color){   pixel amp;= ~(0xFF << (3-color) * 8);   pixel |= value << (3-color) * 8; }
  

Мне нужна помощь, чтобы понять ответ.

Ответ №1:

Хороший способ помочь разобраться с такого рода проблемами — использовать обычную ручку и бумагу. Выберите значения для одной или нескольких переменных, подставьте их внутри выражения. Продолжайте заменять вложенные выражения, пока не будет получен результат.

Подобно тому, как вы упрощаете математические выражения.

Например, с помощью getColorComponent :

Выберите цвет GREEN (со значением 1 ).

Выберите значение пикселя 0x8a2be200 (которое имеет непрозрачный сине-фиолетовый цвет, предполагающий RGBA).

Исходное выражение (pixel >> (3 - color) * 8) amp; 0xff

Цепочка подстановок

  1. (0x8a2be200 >> (3 - 1) * 8) amp; 0xff
  2. (0x8a2be200 >> 2 * 8) amp; 0xff
  3. (0x8a2be200 >> 16) amp; 0xff
  4. 0x8a2b amp; 0xff
  5. 0x2b

С помощью color == GREEN этого извлекается GREEN цветовая составляющая 32-разрядного значения цвета RGBA.

Если вы используете любое из других значений перечисления цветов ( RED , BLUE или ALPHA ), делая то же самое, вы увидите, что он также извлекает эти компоненты из значения цвета RGBA.

Я оставляю это в качестве упражнения для читателей, чтобы использовать эту технику, чтобы выяснить, что setColorComponent делает.


В качестве альтернативы, для использования с компьютерами и отладчиками, разбейте сложное выражение на его наименьшие подвыражения, присвоив результаты временным переменным. Затем используйте отладчик, чтобы пошагово просмотреть код построчно, чтобы увидеть, как объединяются результаты.

При этом выражение (pixel >> (3 - color) * 8) amp; 0xff превратилось бы в инструкции

 auto t1 = 3 - color;     // 3 - color
auto t2 = t1 * 8;        // (3 - color) * 8
auto t3 = pixel >> t2;   // pixel >> (3 - color) * 8
auto t4 = t3 amp; 0xff;     // (pixel >> (3 - color) * 8) amp;0xff