Подтвердить что ты не робот

Примеры объединения в C

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

Так что не стесняйтесь делиться своим профсоюзным взломом (с некоторым объяснением курса:))

4b9b3361

Ответ 1

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

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. В С++ вы можете позволить union быть анонимным. Выбор этого имени может быть трудным. Я имею тенденцию идти с чем-то однобуквенным, поскольку он почти никогда не упоминается в изоляции, и поэтому из контекста всегда ясно, что происходит.

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

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

Здесь я использую тот факт, что struct можно возвращать напрямую и обрабатывать почти как значения примитивного типа (вы можете назначить struct s).

Ответ 2

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

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, которые по умолчанию передают параметры по ссылке. Это означает, что если у вас есть код, который заботится о деталях структуры варианта (например, С++), вызываемых кодом, который не работает (например, VB), тогда вам нужно тщательно разыменовать параметр варианта, если это необходимо.

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

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

Ответ 3

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

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

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

Ответ 4

Пожалуйста, избегайте "хаков" с объединением, они вызывают головные боли переносимости (сущность, проблемы с выравниванием).

  • Допустимое использование объединения - хранить разные типы данных в одном и том же месте, желательно с тегом, чтобы вы знали, какой тип он есть. См. Пример по информации 1800.

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

Ответ 5

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

Ответ 6

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

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

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

Ответ 7

Кстати, я просто использовал один в ответе здесь, чтобы обработать слово, состоящее из 6-битных полей, как два 16-битных целых числа без знака.

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

Ответ 8

#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;

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