C ++ объединяет структуру данных, легкий доступ к битам в DWORD - PullRequest
2 голосов
/ 25 апреля 2010

Я перебираю онлайн учебники по DirectX, и у меня следующая структура:

struct CUSTOMVERTEX
{
FLOAT x, y, z, rhw; // from the D3DFVF_XYZRHW flag
DWORD color;        // from the D3DFVF_DIFFUSE flag
}

Мое базовое понимание DirectX приводит меня к выводу, что цвет состоит из 8-битных альфа, красного, зеленого и синего каналов.

Я пытаюсь получить доступ к этим каналам на восток. Вместо того, чтобы писать следующий код много раз (в структуре CUSTOMVERTEX):

public: int red()
{
    return (color & 0x00FF0000) >> 16;
}

Я мог бы написать более элегантный вариант сочетания союза и структуры, например,

struct CUSTOMVERTEX
{
    FLOAT x, y, z, rhw; // from the D3DFVF_XYZRHW flag

    #pragma pack(2)
    union 
    {
        DWORD color;        // from the D3DFVF_DIFFUSE flag

        struct
        {
            char a;
            char r;
            char g;
            char b;
        };
    };
}

Однако, похоже, это не работает должным образом, значения в r, g, & b выглядят почти так же, как в цвете, например. если цвет 0x12345678 a = 0x78, r = 0x56. Это проблема конечности?

И какие еще проблемы можно ожидать от этого решения? например переполнение от цвета членов?

Полагаю, я спрашиваю: есть ли лучший способ сделать это?!

Ответы [ 3 ]

2 голосов
/ 25 апреля 2010

Да, это проблема с порядком байтов. Если вы поддерживаете только одну платформу, вы можете расположить членов структуры в соответствии с порядком байтов архитектуры. Если вы имеете дело с несколькими архитектурами, вам понадобится #define несколько структурных элементов, в зависимости от порядка байтов.

Структуры и объединения всегда кажутся мне более элегантными, но побитовые операции являются более переносимыми. Когда я делаю подобные вещи, я вставляю утверждение в мой код запуска, чтобы убедиться, что структура соответствует ожидаемому мне размеру, прежде чем наступит неопределенная злобность.

В C ++ вы можете написать класс, который инкапсулирует ваши данные и выполняет ваши операции за вас.

1 голос
/ 25 апреля 2010

Чтобы объединение работало для этого, вам нужно убедиться, что у вас правильные проблемы с порядком байтов, и вам нужно убедиться, что проблемы с заполнением корректны (что потребует нестандартных операторов #pragma или подобных). Даже если вы не заинтересованы в переносимости (DirectX - только для Windows), я все же рекомендую вам использовать встроенные функции для этой цели. Возможно, вам понадобится несколько очень похожих, но я могу утверждать, что сложность этих нескольких функций все еще меньше, чем union. Вероятно, их будет проще понять, у них будет меньше шансов сломаться (особенно без звука), если вы поменяете компиляторы, и следующему парню, читающему код, будет легче быть уверенным, что они делают то, что он ожидает.

В качестве отступления - почему вы использовали #pragma pack(2) вместо #pragma pack(1)?

И если вы используете #pragma pack, не забудьте «сохранить и восстановить» исходные настройки пакета, чтобы другие вещи не работали неожиданно:

#pragma pack(push)
#pragma pack(2)
//...
#pragma pack(pop)
1 голос
/ 25 апреля 2010

Если цвет DWORD равен 0x12345678, байт по адресу и цвету в системе с прямым порядком байтов 0x78.

Уловка с объединением технически приводит к неопределенному поведению. Что не так с методом доступа?

...