Тип союза
Эта статья нуждается в дополнительных цитатах для проверки . ( август 2009 г. ) |
В информатике объединение значение — это , которое может иметь любое из нескольких представлений или форматов в одной и той же области памяти ; который состоит из переменной , которая может содержать такую структуру данных . Некоторые языки программирования поддерживают тип объединения для такого типа данных . Другими словами, тип объединения определяет разрешенные типы, которые могут храниться в его экземплярах, например: float
и integer
. В отличие от записи , которая может содержать как число с плавающей запятой, так и целое число; профсоюз будет состоять только по одному.
Объединение можно представить как участок памяти, используемый для хранения переменных разных типов данных. Как только полю присваивается новое значение, существующие данные заменяются новыми данными. Область памяти, в которой хранится значение, не имеет внутреннего типа (кроме байтов или слов памяти), но значение можно рассматривать как один из нескольких абстрактных типов данных , имеющих тип значения, которое было последним записано в область памяти.
В теории типов объединение имеет тип суммы ; это соответствует несвязному объединению в математике.
В зависимости от языка и типа значение объединения может использоваться в некоторых операциях, таких как присваивание и сравнение на равенство, без знания его конкретного типа. Для других операций эти знания могут потребоваться либо посредством некоторой внешней информации, либо посредством использования тегированного объединения .
Нетегированные союзы
[ редактировать ]Из-за ограничений их использования нетегированные объединения обычно предоставляются только в нетипизированных языках или небезопасным с точки зрения типов способом (как в C ). Они имеют преимущество перед простыми теговыми объединениями, поскольку не требуют места для хранения тега типа данных.
Название «объединение» происходит от формального определения типа. Если тип рассматривать как набор всех значений, которые этот тип может принимать, тип объединения — это просто математическое объединение составляющих его типов, поскольку он может принимать любое значение, которое может принимать любое из его полей. Кроме того, поскольку математическое объединение отбрасывает дубликаты, если более одного поля объединения могут принимать одно общее значение, невозможно по одному значению определить, какое поле было записано последним.
Однако одной из полезных программных функций объединений является сопоставление меньших элементов данных с более крупными для облегчения манипулирования. Структура данных, состоящая, например, из 4 байтов и 32-битного целого числа, может образовывать объединение с беззнаковым 64-битным целым числом и, таким образом, к ней легче получить доступ для целей сравнения и т. д.
Союзы в различных языках программирования
[ редактировать ]АЛГОЛ 68
[ редактировать ]В АЛГОЛе 68 есть тегированные объединения и используется предложение case для различения и извлечения типа компонента во время выполнения. Объединение, содержащее другое объединение, рассматривается как набор всех составляющих его возможностей, и если этого требует контекст, объединение автоматически принудительно превращается в более широкое объединение. Объединение не может явно содержать никаких значений, которые можно различить во время выполнения. Пример:
mode node = union (real, int, string, void); node n := "abc"; case n in (real r): print(("real:", r)), (int i): print(("int:", i)), (string s): print(("string:", s)), (void): print(("void:", "EMPTY")), out print(("?:", n)) esac
Синтаксис типа объединения C/C++ и понятие приведения были заимствованы из АЛГОЛа 68, хотя и в немаркированной форме. [1]
С/С++
[ редактировать ]В C и C++ нетегированные объединения выражаются почти так же, как структуры ( structs ), за исключением того, что каждый элемент данных начинается в одном и том же месте в памяти. Члены данных, как и в структурах, не обязательно должны быть примитивными значениями и фактически могут быть структурами или даже другими объединениями. C++ (начиная с C++11 ) также позволяет члену данных быть любого типа, который имеет полноценный конструктор/деструктор и/или конструктор копирования или нетривиальный оператор присваивания копирования. C++ можно использовать Например, стандартную строку в качестве члена объединения.
Основное использование объединения — предоставление доступа к общему местоположению для разных типов данных, например, доступ к аппаратному вводу/выводу, совместное использование битовых полей и слов или каламбур типов . Объединения также могут обеспечивать низкоуровневый полиморфизм . Однако проверка типов не осуществляется, поэтому программист должен убедиться, что к нужным полям обращаются в разных контекстах. Соответствующее поле переменной объединения обычно определяется состоянием других переменных, возможно, во включающей структуре.
Одна распространенная идиома программирования на языке C использует объединения для выполнения того, что в C++ называется reinterpret_cast
, присваивая одному полю объединения и читая из другого, как это делается в коде, который зависит от необработанного представления значений. Практическим примером является метод вычисления квадратных корней с использованием представления IEEE . Однако в целом это небезопасное использование союзов.
Спецификаторы структуры и объединения имеют одинаковую форму. [ . . . ] Размер союза достаточен, чтобы вместить самого крупного из его членов. Значение не более одного из членов может быть сохранено в объекте объединения в любое время. Указатель на объект объединения, преобразованный соответствующим образом, указывает на каждого из его членов (или, если член является битовым полем, то на единицу, в которой он находится), и наоборот.
— ANSI/ISO 9899:1990 (стандарт ANSI C), раздел 6.5.2.1.
Анонимный союз
[ редактировать ]В C++, C11 и в качестве нестандартного расширения во многих компиляторах объединения также могут быть анонимными. На их элементы данных не требуется ссылка, вместо этого они доступны напрямую. У них есть некоторые ограничения в отличие от традиционных союзов: в С11 они должны быть членом другой структуры или союза; [2] а в C++ у них не может быть методов или спецификаторов доступа.
Простое исключение части синтаксиса, связанной с именем класса, не делает объединение анонимным. Чтобы объединение квалифицировалось как анонимное объединение, объявление не должно объявлять объект. Пример:
#include <iostream>
#include <cstdint>
int main() {
union {
float f;
uint32_t d; // Assumes float is 32 bits wide
};
f = 3.14f;
std::cout << "Hexadecimal representation of 3.14f:"
<< std::hex << d << '\n';
return 0;
}
Анонимные объединения также полезны в C. struct
определения, чтобы обеспечить ощущение пространства имен. [3]
Прозрачный союз
[ редактировать ]В таких компиляторах, как GCC, Clang и IBM XL C для AIX, transparent_union
Атрибут доступен для типов объединения. Типы, содержащиеся в объединении, могут быть прозрачно преобразованы в сам тип объединения при вызове функции при условии, что все типы имеют одинаковый размер. Он в основном предназначен для функций с интерфейсами с несколькими параметрами, использование которого было вызвано необходимостью ранних расширений Unix и последующей рестандартизацией. [4]
КОБОЛ
[ редактировать ]В COBOL элементы данных объединения определяются двумя способами. Первый использует Ключевое слово RENAMES (уровень 66), которое эффективно отображает второй буквенно-цифровой элемент данных поверх той же ячейки памяти, что и предыдущий элемент данных. В приведенном ниже примере кода элемент данных PERSON-REC определяется как группа, содержащая другую группу и элемент числовых данных. PERSON-DATA определяется как буквенно-цифровой элемент данных, который переименовывает PERSON-REC , рассматривая продолжающиеся внутри него байты данных как символьные данные.
01 PERSON-REC.
05 PERSON-NAME.
10 PERSON-NAME-LAST PIC X(12).
10 PERSON-NAME-FIRST PIC X(16).
10 PERSON-NAME-MID PIC X.
05 PERSON-ID PIC 9(9) PACKED-DECIMAL.
01 PERSON-DATA RENAMES PERSON-REC.
Второй способ определить тип объединения — использовать метод Ключевое слово REDEFINES . В приведенном ниже примере кода элемент данных VERS-NUM определяется как 2-байтовое двоичное целое число, содержащее номер версии. Второй элемент данных VERS-BYTES определяется как двухсимвольная буквенно-цифровая переменная. Поскольку второй элемент переопределяется поверх первого, эти два элемента имеют один и тот же адрес в памяти и, следовательно, используют одни и те же базовые байты данных. Первый элемент интерпретирует два байта данных как двоичное значение, а второй элемент интерпретирует байты как символьные значения.
01 VERS-INFO.
05 VERS-NUM PIC S9(4) COMP.
05 VERS-BYTES PIC X(2)
REDEFINES VERS-NUM
Паскаль
[ редактировать ]В Паскале существует два способа создания объединений. Один из них — стандартный путь через вариантную запись. Второй — нестандартный способ объявления переменной как абсолютной, то есть она помещается в ту же ячейку памяти, что и другая переменная, или по абсолютному адресу. Хотя все компиляторы Паскаля поддерживают варианты записей, лишь некоторые поддерживают абсолютные переменные.
Для целей этого примера все целочисленные типы: байт состоит из 8 бит, слово — 16 бит, а целое число — 32 бита.
В следующем примере показана нестандартная абсолютная форма:
var
A: Integer;
B: array[1..4] of Byte absolute A;
C: Integer absolute 0;
В первом примере каждый из элементов массива B отображается в один из конкретных байтов переменной A. Во втором примере переменной C присвоен точный машинный адрес 0.
В следующем примере запись имеет варианты, некоторые из которых находятся в том же месте, что и другие:
type
Shape = (Circle, Square, Triangle);
Dimensions = record
case Figure: Shape of
Circle: (Diameter: real);
Square: (Width: real);
Triangle: (Side: real; Angle1, Angle2: 0..360)
end;
ПЛ/Я
[ редактировать ]В PL/I первоначальный термин для обозначения объединения был ячейка , [5] который до сих пор принимается некоторыми компиляторами как синоним объединения. Объявление объединения аналогично определению структуры, где элементы одного и того же уровня в объявлении объединения занимают одно и то же хранилище. Элементами объединения могут быть данные любого типа, включая структуры и массивы. [6] : стр. 192–193 Здесь vers_num и vers_bytes занимают одни и те же места хранения.
1 vers_info union,
5 vers_num fixed binary,
5 vers_bytes pic '(2)A';
Альтернативой объявлению объединения является атрибут DEFINED, который допускает альтернативные объявления хранилища, однако типы данных базовой и определенной переменных должны совпадать. [6] : стр. 289–293.
Ржавчина
[ редактировать ]Rust реализует как тегированные, так и нетегированные объединения. В Rust теговые объединения реализуются с помощью enum
ключевое слово. В отличие от перечислимых типов в большинстве других языков, варианты перечислений в Rust могут содержать дополнительные данные в форме кортежа или структуры, что делает их тегированными объединениями, а не простыми перечислимыми типами. [7]
Rust также поддерживает объединения без тегов, используя union
ключевое слово. Расположение памяти для объединений в Rust по умолчанию не определено. [8] но союз с #[repr(C)]
Атрибут будет размещен в памяти точно так же, как эквивалентное объединение в C. [9] Чтение полей объединения можно выполнить только внутри unsafe
функция или блок, так как компилятор не может гарантировать, что данные в объединении будут действительны для типа поля; если это не так, это приведет к неопределенному поведению . [10]
Синтаксис и пример
[ редактировать ]С/С++
[ редактировать ]В C и C++ синтаксис следующий:
union <name>
{
<datatype> <1st variable name>;
<datatype> <2nd variable name>;
.
.
.
<datatype> <nth variable name>;
} <union variable name>;
Структура также может быть членом объединения, как показано в следующем примере:
union name1
{
struct name2
{
int a;
float b;
char c;
} svar;
int d;
} uvar;
В этом примере определяется переменная uvar
как союз (помеченный как name1
), который содержит два элемента, структуру (помеченную как name2
) по имени svar
(которая, в свою очередь, содержит три элемента) и целочисленную переменную с именем d
.
Объединения могут возникать внутри структур и массивов, и наоборот:
struct
{
int flags;
char *name;
int utype;
union {
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. [11] Значения неявно «помечены» типом языка и могут быть получены с помощью «gettype()».
class Example
{
private int|float $foo;
public function squareAndAdd(float|int $bar): int|float
{
return $bar ** 2 + $this->foo;
}
}
Питон
[ редактировать ]Поддержка ввода была введена в Python 3.5. [12] Новый синтаксис для типов объединения был представлен в Python 3.10. [13]
class Example:
foo = 0
def square_and_add(self, bar: int | float) -> int | float:
return bar ** 2 + self.foo
Машинопись
[ редактировать ]Типы объединения поддерживаются в TypeScript. [14] Значения неявно «помечены» типом языка и могут быть получены с помощью typeof
призывать к примитивным ценностям и instanceof
сравнение сложных типов данных. Типы с перекрывающимся использованием (например, метод среза существует как для строк, так и для массивов, оператор плюс работает как со строками, так и с числами) не требуют дополнительного сужения для использования этих функций.
function successor(n: number | bigint): number | bigint {
// types that support the same operations don't need narrowing
return ++n;
}
function dependsOnParameter(v: string | Array<string> | number) {
// distinct types need narrowing
if (v instanceof Array) {
// do something
} else if (typeof(v) === "string") {
// do something else
} else {
// has to be a number
}
}
Ржавчина
[ редактировать ]Теговые объединения в Rust используют enum
ключевое слово и может содержать варианты кортежа и структуры:
enum Foo {
Bar(i32),
Baz { x: String, y: i32 },
}
Немаркированные объединения в Rust используют union
ключевое слово:
union Foo {
bar: i32,
baz: bool,
}
Чтение полей нетегированного объединения приводит к неопределенному поведению , если данные в объединении не соответствуют типу поля и, следовательно, требуют unsafe
блокировать:
let x = Foo { bar: 10 };
let y = unsafe { x.bar }; // This will set y to 10, and does not result in undefined behavior.
let z = unsafe { x.baz }; // This results in undefined behavior, as the value stored in x is not a valid bool.
Ссылки
[ редактировать ]- ^ Ричи, Деннис М. (март 1993 г.). «Развитие языка Си» . Уведомления ACM SIGPLAN . 28 (3): 201–208. дои : 10.1145/155360.155580 .
Схема композиции типов, принятая К., во многом обязана Алголу 68, хотя, возможно, она не появилась в форме, которую одобрили бы приверженцы Алгола. Центральным понятием, которое я усвоил из Алгола, была структура типов, основанная на атомарных типах (включая структуры), состоящих из массивов, указателей (ссылок) и функций (процедур). Концепция объединений и приведения Алгола 68 также оказала влияние, появившееся позже.
- ^ «6.63 Безымянная структура и поля объединения» . Проверено 29 декабря 2016 г.
- ^ Зибенманн, Крис. «CUnionsForNamespaces» . utcc.utoronto.ca .
- ^ «Общие атрибуты типа: Transparent_union» . Использование коллекции компиляторов GNU (GCC) .
- ^ Корпорация IBM (март 1968 г.). Спецификации языка IBM System/360 PL/I (PDF) . п. 52 . Проверено 22 января 2018 г.
- ^ Перейти обратно: а б Корпорация IBM (декабрь 2017 г.). Enterprise PL/I для z/OS PL/I для AIX IBM Developer для z Systems PL/I для Windows Справочник по языку (PDF) . Проверено 22 января 2018 г.
- ^ «Как Rust реализует тегированные союзы — Пэт Шонесси» . patshaughnessy.net . Проверено 25 апреля 2023 г.
- ^ «Типы объединения — Справочник по Rust» . doc.rust-lang.org . Проверено 25 апреля 2023 г.
- ^ «Макет текста — Справочник по Rust» . doc.rust-lang.org . Проверено 25 апреля 2023 г.
- ^ «Профсоюзы — Справочник по ржавчине» . doc.rust-lang.org . Проверено 25 апреля 2023 г.
- ^ Карунаратне, Айеш. «PHP 8.0: Типы объединения» . PHP.Смотреть . Проверено 30 ноября 2020 г. .
- ^ «Ввод текста — Поддержка подсказок типов — Документация Python 3.9.7» . docs.python.org . Проверено 8 сентября 2021 г.
- ^ «PEP 604 — Разрешить запись типов объединения как X | Y» . Python.org . Проверено 8 сентября 2021 г.
- ^ «Справочник – Союзы и виды пересечений» . www.typescriptlang.org . Проверено 30 ноября 2020 г. .
- Керниган, Брайан В.; Ричи, Деннис М. (1978). Язык программирования C (1-е изд.). Прентис Холл. п. 138 . ISBN 978-0131101630 . Проверено 23 января 2018 г.
Внешние ссылки
[ редактировать ]- boost::variant — типобезопасная альтернатива объединениям C++.
- MSDN: Классы, структуры и союзы , примеры и синтаксис.
- различия , различия между объединением и структурой
- Разница между структурой и объединением в C++