Примеры объединения в [закрытом] C

32
задан timrau 14 August 2012 в 17:52
поделиться

8 ответов

Один классик должен представить значение "неизвестного" типа, как в ядре упрощенной виртуальной машины:

typedef enum { INTEGER, STRING, REAL, POINTER } Type;

typedef struct
{
  Type type;
  union {
  int integer;
  char *string;
  float real;
  void *pointer;
  } x;
} Value;

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

Так как это находится в (старо, pre-C11) C, внутреннему объединению нужно дать имя поля во внешнем struct. В C++ можно позволить union будьте анонимными. Выбор этого имени может быть трудным. Я склонен идти с чем-то одно-буквой, так как на нее почти никогда не ссылаются в изоляции, и таким образом всегда ясно из контекста, что продолжается.

Код для устанавливания значения к целому числу мог бы быть похожим на это:

Value value_new_integer(int v)
{
  Value v;
  v.type = INTEGER;
  v.x.integer = v;
  return v;
}

Здесь я использую факт это structs можно возвратить непосредственно и рассматривать почти как значения типа примитива (можно присвоиться structs).

37
ответ дан 27 November 2019 в 20:20
поделиться

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

union {
    char c;
    int i;
    string *s;
    double d;
    Expression *e;
    ExpressionList *el;
    fpos_t fp;
}

Объединение используется для соединения семантических значений с маркерами лексического анализатора и производством синтаксического анализатора. Эта практика является довольно обычной в генераторах грамматики, как yacc, который оказывает явную поддержку для нее. Объединение может содержать любое из своих значений, но только одного из них в то время. Например, в любой точке из входного файла Вы или считали символьную константу (сохраненный в c), или целое число (сохраненный в i) или число с плавающей точкой (сохраненный в d). Генератор грамматики оказывает значительную помощь для определения, которое из значений хранится в любой момент в зависимости от обрабатываемого правила.

8
ответ дан 27 November 2019 в 20:20
поделиться

Вот немного один, я использую каждый день:

struct tagVARIANT {
    union {
        struct __tagVARIANT {
            VARTYPE vt;
            WORD    wReserved1;
            WORD    wReserved2;
            WORD    wReserved3;
            union {
                LONG          lVal;         /* VT_I4                */
                BYTE          bVal;         /* VT_UI1               */
                SHORT         iVal;         /* VT_I2                */
                FLOAT         fltVal;       /* VT_R4                */
                DOUBLE        dblVal;       /* VT_R8                */
                VARIANT_BOOL  boolVal;      /* VT_BOOL              */
                _VARIANT_BOOL bool;         /* (obsolete)           */
                SCODE         scode;        /* VT_ERROR             */
                CY            cyVal;        /* VT_CY                */
                DATE          date;         /* VT_DATE              */
                BSTR          bstrVal;      /* VT_BSTR              */
                IUnknown *    punkVal;      /* VT_UNKNOWN           */
                IDispatch *   pdispVal;     /* VT_DISPATCH          */
                SAFEARRAY *   parray;       /* VT_ARRAY             */
                BYTE *        pbVal;        /* VT_BYREF|VT_UI1      */
                SHORT *       piVal;        /* VT_BYREF|VT_I2       */
                LONG *        plVal;        /* VT_BYREF|VT_I4       */
                FLOAT *       pfltVal;      /* VT_BYREF|VT_R4       */
                DOUBLE *      pdblVal;      /* VT_BYREF|VT_R8       */
                VARIANT_BOOL *pboolVal;     /* VT_BYREF|VT_BOOL     */
                SCODE *       pscode;       /* VT_BYREF|VT_ERROR    */
                CY *          pcyVal;       /* VT_BYREF|VT_CY       */
                DATE *        pdate;        /* VT_BYREF|VT_DATE     */
                BSTR *        pbstrVal;     /* VT_BYREF|VT_BSTR     */
                IUnknown **   ppunkVal;     /* VT_BYREF|VT_UNKNOWN  */
                IDispatch **  ppdispVal;    /* VT_BYREF|VT_DISPATCH */
                SAFEARRAY **  pparray;      /* VT_BYREF|VT_ARRAY    */
                VARIANT *     pvarVal;      /* VT_BYREF|VT_VARIANT  */
                PVOID         byref;        /* Generic ByRef        */
                CHAR          cVal;         /* VT_I1                */
                USHORT        uiVal;        /* VT_UI2               */
                ULONG         ulVal;        /* VT_UI4               */
                INT           intVal;       /* VT_INT               */
                UINT          uintVal;      /* VT_UINT              */
                DECIMAL *     pdecVal;      /* VT_BYREF|VT_DECIMAL  */
                CHAR *        pcVal;        /* VT_BYREF|VT_I1       */
                USHORT *      puiVal;       /* VT_BYREF|VT_UI2      */
                ULONG *       pulVal;       /* VT_BYREF|VT_UI4      */
                INT *         pintVal;      /* VT_BYREF|VT_INT      */
                UINT *        puintVal;     /* VT_BYREF|VT_UINT     */
            } __VARIANT_NAME_3;
        } __VARIANT_NAME_2;
        DECIMAL decVal;
    } __VARIANT_NAME_1;
};

Это - определение типа данных варианта автоматизации OLE. Поскольку Вы видите, что это имеет много возможных типов. Существует много правил вокруг типов, которые можно использовать в различных ситуациях, в зависимости от поддержки намеченного клиентского кода. Не все типы поддерживаются всеми языками.

Типы с VT_BYREF после них используются языками, такими как VBScript, которые передают параметры ссылкой по умолчанию. Это означает, есть ли у Вас некоторый код, который заботится о различных деталях структуры (таких как C++) о быть названным кодом, который не делает (такие как VB), затем необходимо тщательно разыменовать различный параметр при необходимости.

Типы byref также используются для возвращения значения от функций. Существует также поддержка типов массива с помощью неверно названного удачливого SAFEARRAY введите - настолько трудный использовать от C++.

Если у Вас есть массив строк, можно передать его vbscript, но он не может использоваться (кроме распечатать размер). Для фактического чтения значений данные массива должны иметь тип VT_BYREF | VT_BSTR.

10
ответ дан 27 November 2019 в 20:20
поделиться

Избегайте "взломов" с объединением, они вызывают головные боли мобильности (порядок байтов, проблемы выравнивания).

  • Законное использование объединения должно сохранить различные типы данных в том же месте, предпочтительно с тегом так, чтобы Вы знали, какой тип это. Посмотрите пример к 1800 ИНФОРМАЦИЯ.

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

7
ответ дан 27 November 2019 в 20:20
поделиться

Мы используем объединения для упакованных сообщений на работе (C/C++), таким образом, мы можем раздать структуру с объединением как элемент данных, затем получите доступ к корректному пути на основе идентификационного поля в структуре.

Хорошо работавший, пока кто-то не записал структуру в файл, теперь мы ограничены самыми большими данными, используемыми в файле, потому что даже при том, что существует версия файла, никто никогда не изменял его....

Таким образом, в то время как полезный для работы в оперативной памяти, постарайтесь не вслепую писать им в диск или сеть.

4
ответ дан 27 November 2019 в 20:20
поделиться
struct InputEvent
{
    enum EventType
    {
        EventKeyPressed,
        EventKeyPressRepeated,
        EventKeyReleased,
        EventMousePressed,
        EventMouseMoved,
        EventMouseReleased
    } Type;
    union
    {
        unsigned int KeyCode;
        struct
        {
            int x;
            int y;
            unsigned int ButtonCode;
        };
    };
};
...
std::vector<InputEvent>   InputQueue;

со взломом объединения я могу просто сделать вектор объектов. Я уверен, что это могло быть сделано более чистым..., но это работает на меня - KISS

3
ответ дан 27 November 2019 в 20:20
поделиться

По совпадению я просто использовал один в ответе Stackoverflow здесь, таким образом, я мог рассматривать слово, которое было составлено из 6 битовых полей как два целых числа без знака на 16 битов.

Несколько лет назад, я также использовал один для (первое) компилятор C ARM - инструкции в те дни составляли все 32 бита, но имели различные разметки в зависимости от точной инструкции. Таким образом, у меня было объединение для представления инструкции ARM, содержа ряд структур, которые у каждого были соответствующие битовые поля для типа конкретной инструкции.

2
ответ дан 27 November 2019 в 20:20
поделиться
#define DWORD unsigned int
#define WORD  unsigned short
#define BYTE  unsigned char

typedef union _DWORD_PART_ {

   DWORD dwWord;

   struct {
      WORD dwMSB;
      WORD dwLSB;
   }hw;

   struct {

      BYTE byMSB;
      BYTE byMSBL;
      BYTE byLSBH;
      BYTE byLSB;

   } b;

} DWORD_PART;

Это - простой способ получить доступ к частям слов. (После того как Вы сделаны, любое изменение в порядке байтов платформы может также быть обработано легко),

1
ответ дан 27 November 2019 в 20:20
поделиться
Другие вопросы по тегам:

Похожие вопросы: