Из Википедии, бесплатной энциклопедии
  (Перенаправлено из Союза (информатика) )
Перейти к навигации Перейти к поиску

В информатике , А объединение является значением , которое может иметь любой из нескольких представлений или форматов в пределах одной и той же позиции в памяти ; который состоит из переменной, которая может содержать такую структуру данных . Некоторые языки программирования поддерживают специальные типы данных , называемые типами объединения , для описания таких значений и переменных. Другими словами, определение типа объединения будет указывать, какой из ряда разрешенных типов примитивов может храниться в его экземплярах, например, «с плавающей запятой или длинное целое число». В отличие от записи (или структуры), которая может содержать float ицелое число; в объединении в любой момент времени может быть только одно значение.

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

В теории типов объединение имеет тип суммы ; это соответствует несвязному объединению в математике.

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

Союзы без тегов [ править ]

Из-за ограничений использования немаркированные объединения обычно предоставляются только на нетипизированных языках или небезопасным для типов способом (как в C ). У них есть преимущество перед простыми помеченными объединениями в том, что они не требуют места для хранения тега типа данных.

Название «объединение» происходит от формального определения типа. Если тип рассматривается как набор всех значений, которые может принимать этот тип, тип объединения - это просто математическое объединение составляющих его типов, поскольку он может принимать любое значение, которое может принимать любое из его полей. Кроме того, поскольку математическое объединение отбрасывает дубликаты, если несколько полей объединения могут принимать одно общее значение, по одному только значению невозможно определить, какое поле было записано последним.

Однако одна полезная программная функция объединений состоит в том, чтобы отображать меньшие элементы данных в более крупные для упрощения манипуляции. Структура данных, состоящая, например, из 4 байтов и 32-битного целого числа, может образовывать объединение с 64-битным целым числом без знака, и, таким образом, к ней будет легче получить доступ для сравнения и т. Д.

Союзы на разных языках программирования [ править ]

АЛГОЛ 68 [ править ]

АЛГОЛ 68 имеет теги для объединений и использует предложение case, чтобы различать и извлекать составляющий тип во время выполнения. Объединение, содержащее другое объединение, рассматривается как набор всех составляющих его возможностей.

Синтаксис типа union C / C ++ и понятие приведения типов были унаследованы от АЛГОЛА 68, но в немаркированной форме. [1]

C / C ++ [ править ]

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

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

Основное использование объединения - это разрешение доступа к общему расположению для разных типов данных, например, аппаратный доступ к вводу / выводу, совместное использование битовых полей и слов или перенаправление типов . Союзы также могут обеспечивать низкоуровневый полиморфизм . Однако здесь нет проверки типов, поэтому программист должен быть уверен, что правильные поля доступны в разных контекстах. Соответствующее поле переменной объединения обычно определяется состоянием других переменных, возможно, во внешней структуре.

Одна распространенная идиома программирования C использует объединения для выполнения того, что C ++ называет reinterpret_cast , путем присвоения одному полю объединения и чтения из другого, как это делается в коде, который зависит от необработанного представления значений. Практическим примером является метод вычисления квадратных корней с использованием представления IEEE . Однако это небезопасное использование профсоюзов в целом.

Спецификаторы структуры и объединения имеют одинаковую форму. [. . . ] Размер объединения достаточен для того, чтобы в нем мог быть самый большой из его членов. Значение не более одного из членов может быть сохранено в объекте union в любое время. Указатель на объект объединения, преобразованный соответствующим образом, указывает на каждый из его членов (или, если член является битовым полем, то на единицу, в которой он находится), и наоборот.

-  ANSI / ISO 9899: 1990 (стандарт ANSI C), раздел 6.5.2.1

Анонимный союз [ править ]

В C ++, C11 и в качестве нестандартного расширения во многих компиляторах объединения также могут быть анонимными. На их элементы данных не нужно ссылаться, вместо этого к ним осуществляется прямой доступ. У них есть некоторые ограничения в отличие от традиционных объединений: в C11 они должны быть членами другой структуры или объединения [2], а в C ++ они не могут иметь методов или спецификаторов доступа.

Простое исключение части синтаксиса имени класса не делает объединение анонимным. Чтобы объединение могло считаться анонимным объединением, объявление не должно объявлять объект. Пример:

#include  <iostream>#include  <cstdint>int  main ()  {  с использованием  пространства имен  std ; союз  {  float  f ;  uint32_t  d ;  // Предполагается, что число с плавающей запятой имеет ширину 32 бита  }; f  =  3,14f ;  cout  <<  "Двоичное представление 3.14 ="  <<  hex  <<  d  <<  endl ; возврат  0 ; }

Прозрачный союз [ править ]

В Unix-подобных компиляторах, таких как GCC, Clang и IBM XL C для AIX, transparent_unionатрибут доступен для типов объединения. Типы, содержащиеся в объединении, могут быть прозрачно преобразованы в сам тип объединения при вызове функции при условии, что все типы имеют одинаковый размер. Он в основном предназначен для работы с интерфейсами с несколькими параметрами, использование которых требовалось ранними расширениями Unix и последующей повторной стандартизацией. [3]

КОБОЛ [ править ]

В COBOL элементы данных объединения определяются двумя способами. Первый использует ключевое слово RENAMES (уровень 66), которое эффективно отображает второй буквенно-цифровой элемент данных поверх того же места в памяти, что и предыдущий элемент данных. В приведенном ниже примере кода элемент данных PERSON-REC определяется как группа, содержащая другую группу и числовой элемент данных. PERSON-DATA определяется как буквенно-цифровой элемент данных, который переименовывает PERSON-REC , обрабатывая байты данных, продолжающиеся в нем, как символьные данные.

 01 ПЕРСОНА-РЕК . 05 ИМЯ ЛИЦА . 10 ФИО-ПОСЛЕДНИЙ ФОТО X (12) . 10 ИМЯ-ПЕРВОЕ ФОТО X (16) . 10 ПЕРСОНА-ИМЯ-MID ПОС Х . 05 PERSON-ID PIC 9 (9) PACKED-DECIMAL .               01 PERSON -DATA  ПЕРЕИМЕНОВАТЬ PERSON  -REC .

Второй способ определить тип объединения - использовать ключевое слово REDEFINES . В приведенном ниже примере кода элемент данных VERS-NUM определяется как 2-байтовое двоичное целое число, содержащее номер версии. Второй элемент данных VERS-BYTES определяется как двухсимвольная буквенно-цифровая переменная. Поскольку второй элемент переопределяется по первому элементу, два элемента используют один и тот же адрес в памяти и, следовательно, используют одни и те же базовые байты данных. Первый элемент интерпретирует два байта данных как двоичное значение, а второй элемент интерпретирует байты как символьные значения.

 01 ВЕРС-ИНФОРМАЦИЯ . 05 НОМЕР ВЕРСИЙ PIC S9 (4) КОМП . 05 ВЭРЗЛИ-БАЙТЫ ПОС Х (2) переопределяет ВЭРЗ-NUM        

Паскаль [ править ]

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

Для целей этого примера все следующие типы являются целыми числами: байт - 8 бит, слово - 16 бит, а целое число - 32 бита.

В следующем примере показана нестандартная абсолютная форма:

VAR  A :  целое число ;  Б :  массив [ 1 .. 4 ]  из  байт  абсолютного  A ;  C :  целое число,  абсолютный  0 ;

В первом примере каждый из элементов массива B отображается на один из конкретных байтов переменной A. Во втором примере переменной C присваивается точный машинный адрес 0.

В следующем примере у записи есть варианты, некоторые из которых имеют то же расположение, что и другие:

ТИП  TSystemTime  =  запись  Год ,  Месяц ,  DayOfWeek ,  День  :  слово ;  Час ,  Минута ,  Секунда ,  Миллисекунда :  слово ;  конец  ;  TGender  =  ( мужчина ,  женщина ,  TransFemale ,  TransMale ,  Другое ) ;  TPerson  =  RECORD  FirstName , Lastname :  Строка ;  Дата рождения : TSystemTime ;  Зависимые :  целое число ;  HourlyRate :  Валюта ;  Дело  Пол : TGender  из  Женщины ,  TransMale :  ( isPregnant :  Boolean ;  DateDue : TSystemTime ) ;  Мужчина ,  TransFemale :  ( HasPartner ,  isPartnerExpecting : Boolean ;  PartnerDate :  TSystemTime ) ;  КОНЕЦ ;

В приведенном выше примере запись Tperson имеет поле тега Gender , и тег делит людей на два класса: женщины или транс-мужчины (человек с гендерной идентичностью мужского пола, но родился с женским телом) и мужчина или транс-женщина (человек с гендерной идентичностью женского пола, но рожденный в мужском теле). В этой записи hasPartner и isPregnant занимают одно и то же расположение, а DateDue и isPartnerExpecting имеют одно и то же расположение. Хотя в записи есть поле тега Gender , компилятор не обеспечивает доступ в соответствии со значением тега: можно получить доступ к любому из полей вариантов независимо от значения тега, например, если пол другойявляется значением поля тега Gender , любое из вариантов поля все еще может быть доступно.

PL / I [ править ]

В PL / I , то оригинальный термин для объединения был клетка , [4] , который до сих пор принимается как синоним для объединения нескольких трансляторов. Объявление union аналогично определению структуры, где элементы на одном уровне в объявлении union занимают одно и то же хранилище. Элементы объединения могут быть любого типа данных, включая структуры и массивы. [5] : pp192–193 Здесь vers_num и vers_bytes занимают одни и те же места хранения.

 1 объединение vers_info  , 5 фиксированных двоичных чисел vers_num , 5 байтов vers_bytes pic '(2) A';     

Альтернативой объявлению объединения является атрибут DEFINED, который допускает альтернативные объявления хранилища, однако типы данных базовой и определенной переменных должны совпадать. [5] : стр.289–293

Синтаксис и пример [ править ]

C / C ++ [ править ]

В C и C ++ синтаксис:

объединение  < имя > {  < тип данных >  < 1 - й  переменной  имя > ;  < Типа данные >  < 2 - й  переменного  имя > ;  .  .  .  < тип данных >  < имя n-й  переменной  > ; } < имя переменной объединения > ;   

Структура также может быть членом объединения, как показано в следующем примере:

объединение  name1 {  struct  name2  {  int  a ;  float  b ;  char  c ;  }  свар ;  int  d ; }  увар ;

В этом примере переменная определяется uvarкак объединение (помечено как name1), которое содержит два члена, структуру (помеченную как name2) с именем svar(которая, в свою очередь, содержит три члена) и целочисленную переменную с именем d.

Объединения могут происходить внутри структур и массивов, и наоборот:

struct {  int  flags ;  char  * имя ;  int  utype ;  союз  {  int  ival ;  float  fval ;  char  * sval ;  }  u ; }  symtab [ NSYM ];

Число ival обозначается как, symtab[i].u.ivalа первый символ строки sval обозначается одним из *symtab[i].u.svalили symtab[i].u.sval[0].

PHP [ править ]

Типы объединения были введены в PHP 8.0. [6]

 Пример класса {  private  int | float  $ foo ; публичная  функция  squareAndAdd ( float | int  $ bar ) :  int | float  {  return  $ bar  **  2  +  $ this -> foo ;  } }

TypeScript [ править ]

Типы объединения поддерживаются в TypeScript. [7]

 преемник функции ( n : число  |  bigint ) :  число  |  bigint  {  return  ++ n }

Разница между союзом и структурой [ править ]

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

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

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

В качестве примера, иллюстрирующего этот момент, объявление

struct  foo  {  int  a ;  float  b ;  }

определяет объект данных с двумя членами, занимающими последовательные ячейки памяти:

 ┌─────┬─────┐ фу │ а │ б │ └─────┴─────┘ ↑ ↑Адрес памяти: 0150 0154

Напротив, декларация

объединение  бар  {  int  a ;  float  b ;  }

определяет объект данных с двумя членами, занимающими одно и то же место в памяти:

 ┌─────┐ бар │ а │ │ б │ └─────┘Адрес памяти: 0150

Структуры используются там, где «объект» состоит из других объектов, например, точечный объект, состоящий из двух целых чисел, являющихся координатами x и y:

typedef  struct  {  int  x ;  // x и y разделены  int  y ; }  tPoint ;

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

typedef  перечисление  {  STR ,  INT  }  tType ; typedef  struct  {  tType  typ ;  // тип отдельный.  союз  {  int  ival ;  // ival и sval занимают одну и ту же память.  char  * sval ;  }; }  tVal ;

См. Также [ править ]

  • Tagged union
  • Оператор UNION
  • Тип варианта

Ссылки [ править ]

  1. ^ Ричи, Деннис М. (март 1993). «Развитие языка Си» . Уведомления ACM SIGPLAN . 28 (3): 201–208. DOI : 10.1145 / 155360.155580 . Схема набора шрифтов, принятая в Си, в значительной степени обязана Алголу 68, хотя, возможно, она не возникла в той форме, которую одобрили бы приверженцы Алгола. Центральным понятием, которое я уловил из Алгола, была структура типов, основанная на атомарных типах (включая структуры), составленных в массивы, указатели (ссылки) и функции (процедуры). Концепция объединений и преобразований в Алголе 68 также оказала влияние, появившееся позже.
  2. ^ «6.63 Безымянная структура и поля объединения» . Проверено 29 декабря 2016 .
  3. ^ «Атрибуты общего типа: transparent_union» . Использование коллекции компиляторов GNU (GCC) .
  4. ^ Корпорация IBM (март 1968 г.). Спецификации языка IBM System / 360 PL / I (PDF) . п. 52 . Проверено 22 января 2018 года .
  5. ^ a b Корпорация IBM (декабрь 2017 г.). Enterprise PL / I для z / OS PL / I для AIX IBM Developer для z Systems PL / I для Windows Справочник по языку (PDF) . Проверено 22 января 2018 года .
  6. ^ Karunaratne, Айеш. «PHP 8.0: типы объединения» . PHP.Watch . Проверено 30 ноября 2020 .
  7. ^ «Справочник - Союзы и типы пересечений» . www.typescriptlang.org . Проверено 30 ноября 2020 .
  • Керниган, Брайан В .; Ричи, Деннис М. (1978). Язык программирования C (1-е изд.). Прентис Холл. п. 138 . ISBN 978-0131101630. Проверено 23 января 2018 года .

Внешние ссылки [ править ]

  • boost :: variant , безопасная альтернатива объединениям C ++
  • MSDN: классы, структуры и союзы , примеры и синтаксис
  • различия , различия между союзом и структурой
  • Разница между структурой и объединением в C ++