Typ unie - Union type

Ve vědě o počítačích , je svazek je hodnota, která může mít některý z několika prohlášení nebo formátů ve stejné pozici v paměti ; který se skládá z proměnné, která může obsahovat takovou datovou strukturu . Některé programovací jazyky podporují speciální datové typy , nazývané sjednocené typy , k popisu takových hodnot a proměnných. Jinými slovy, definice typu sjednocení specifikuje, který z řady povolených primitivních typů může být uložen v jeho instancích, např. „Float or long integer“. Na rozdíl od záznamu (nebo struktury), který by mohl být definován tak, aby obsahoval float a celé číslo; v unii existuje v daném okamžiku pouze jedna hodnota.

Sjednocení lze zobrazit jako kus paměti, který se používá k ukládání proměnných různých datových typů. Jakmile je k poli přiřazena nová hodnota, stávající data se přepíší novými daty. Oblast paměti uchovávající hodnotu nemá žádný vnitřní typ (jiný než jen bajty nebo slova paměti), ale s hodnotou lze zacházet jako s jedním z abstraktních datových typů , které mají typ hodnoty, která byla naposledy zapsána do oblasti paměti.

V teorii typů má unie typ součtu ; to odpovídá nesouvislému spojení v matematice.

V závislosti na jazyce a typu může být v některých operacích, jako je přiřazení a porovnání pro rovnost, použita sjednocená hodnota , aniž by byl znám její konkrétní typ. Jiné operace mohou vyžadovat tyto znalosti, buď pomocí externích informací, nebo pomocí označeného svazku .

Neoznačené odbory

Vzhledem k omezením jejich použití jsou neoznačené svazky obecně poskytovány pouze v nezadaných jazycích nebo způsobem, který není bezpečný pro typ (jako v jazyce C ). Mají výhodu oproti jednoduchým označeným svazkům, že nevyžadují místo pro uložení značky datového typu.

Název „unie“ pochází z formální definice typu. Pokud je typ považován za množinu všech hodnot, které tento typ může nabývat, je typ sjednocení jednoduše matematickým spojením jeho konstituujících typů, protože může nabývat jakékoli hodnoty, kterou může mít kterékoli z jeho polí. Protože také matematický svaz zahodí duplikáty, pokud více než jedno pole sjednocení může mít jednu společnou hodnotu, nelze podle samotné hodnoty zjistit, které pole bylo naposledy zapsáno.

Jednou užitečnou programovací funkcí svazků je však mapování menších datových prvků na větší pro snadnější manipulaci. Datová struktura skládající se například ze 4 bajtů a 32bitového celého čísla může tvořit sjednocení s 64bitovým celým číslem bez znaménka, a je tak snadněji přístupná pro účely srovnání atd.

Odbory v různých programovacích jazycích

ALGOL 68

ALGOL 68 označil odbory a používá klauzuli case k rozlišení a extrahování typu součásti za běhu. Spojení obsahující jiný svaz je považováno za soubor všech jeho základních možností.

Syntaxe typu spojení C/C ++ a pojem přetypování byla odvozena z ALGOL 68, i když v neoznačené formě.

C/C ++

V C a C ++ jsou neoznačené svazky vyjádřeny téměř přesně jako struktury ( struktury ), kromě toho, že každý datový člen začíná na stejném místě v paměti. Datové členy, jako ve strukturách, nemusí být primitivní hodnoty a ve skutečnosti to mohou být struktury nebo dokonce jiné svazky. C ++ (od C ++ 11 ) také umožňuje, aby datovým členem byl jakýkoli typ, který má plnohodnotný konstruktor/destruktor a/nebo konstruktor kopií nebo netriviální operátor přiřazení kopií. Je například možné mít standardní řetězec C ++ jako člena unie.

Stejně jako struktura jsou všichni členové unie ve výchozím nastavení veřejní. Klíčová slova private, publica protectedmůže být použit uvnitř struktury nebo unie v přesně stejným způsobem jsou používány uvnitř třídy pro definování soukromé, veřejné a chráněný přístup člena.

Primární použití unie je umožnění přístupu ke společnému umístění různými datovými typy, například hardwarovým vstupním/výstupním přístupem, sdílením bitového pole a slov nebo typem punningu . Odbory mohou také poskytovat nízkoúrovňový polymorfismus . Neexistuje však žádná kontrola typů, takže je na programátorovi, aby si byl jistý, že ke správným polím se přistupuje v různých kontextech. Příslušné pole sjednocené proměnné je obvykle určeno stavem jiných proměnných, případně v uzavírací struktuře.

Jeden společný C programovací idiom používá odbory k provedení toho, co C ++ nazývá reinterpret_cast , přiřazením k jednomu poli sjednocení a čtením z jiného, ​​jak se provádí v kódu, který závisí na nezpracované reprezentaci hodnot. Praktickým příkladem je metoda výpočtu odmocnin pomocí reprezentace IEEE . Nejedná se však o bezpečné používání odborů obecně.

Specifikátory struktury a sjednocení mají stejnou formu. [. . . ] Velikost unie je dostačující na to, aby obsahovala největší z jejích členů. Hodnotu nejvýše jednoho z členů lze kdykoli uložit do objektu sjednocení . Ukazatel na sjednocený objekt, vhodně převedený, ukazuje na každý jeho člen (nebo pokud je člen bitové pole, pak na jednotku, ve které je umístěn) a naopak.

-  ANSI/ISO 9899: 1990 (norma ANSI C), část 6.5.2.1

Anonymní unie

V C ++, C11 a jako nestandardní rozšíření v mnoha kompilátorech mohou být odbory také anonymní. Na jejich datové členy není třeba odkazovat, místo toho se k nim přistupuje přímo. Na rozdíl od tradičních svazků mají určitá omezení: v C11 musí být členem jiné struktury nebo unie a v C ++ nemohou mít metody ani přístupové specifikátory.

Pouhé vynechání části syntaxe název-třídy neudělá z unie anonymní sjednocení. Aby se odbor kvalifikoval jako anonymní svaz, deklarace nesmí deklarovat objekt. Příklad:

#include <iostream>
#include <cstdint>

int main() {
   union {
      float f;
      std::uint32_t d; // Assumes float is 32 bits wide
   };

   f = 3.14f;
   std::cout << "Hexadecimal representation of 3.14f:" 
             << std::hex << d << '\n';
}

Anonymní svazky jsou také užitečné v structdefinicích C, aby poskytovaly pocit jmenného prostoru.

Transparentní unie

V kompilátorech podobných Unixu, jako jsou GCC, Clang a IBM XL C pro AIX, je transparent_unionatribut dostupný pro typy sjednocení. Typy obsažené ve sjednocení lze transparentně převést na samotný typ sjednocení ve volání funkce za předpokladu, že všechny typy mají stejnou velikost. Je určen hlavně pro funkci s více parametrovými rozhraními, což je použití vyžadované dřívějšími unixovými rozšířeními a pozdější re-standardizací.

COBOL

V COBOL jsou položky sjednocených dat definovány dvěma způsoby. První používá klíčové slovo RENAMES (úroveň 66), které efektivně mapuje druhou alfanumerickou datovou položku na stejné místo v paměti jako předchozí datová položka. V níže uvedeném příkladu kódu je datová položka PERSON-REC definována jako skupina obsahující jinou skupinu a číselnou datovou položku. PERSON-DATA je definována jako alfanumerická datová položka, která přejmenuje PERSON-REC , přičemž datové bajty v ní pokračující budou považovány za znaková data.

  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.

Druhým způsobem, jak definovat typ sjednocení, je použití klíčového slova REDEFINES . V níže uvedeném příkladu kódu je datová položka VERS-NUM definována jako dvoubajtové binární celé číslo obsahující číslo verze. Druhá datová položka VERS-BYTES je definována jako dvouznaková alfanumerická proměnná. Protože je druhá položka předefinována na první položku, sdílejí tyto dvě položky v paměti stejnou adresu, a proto sdílejí stejné základní datové bajty. První položka interpretuje dva datové bajty jako binární hodnotu, zatímco druhá položka interpretuje bajty jako znakové hodnoty.

  01  VERS-INFO.
      05  VERS-NUM        PIC S9(4) COMP.
      05  VERS-BYTES      PIC X(2)
                          REDEFINES VERS-NUM

Pascal

V Pascalu existují dva způsoby vytváření svazků. Jedním z nich je standardní způsob procházení variantního záznamu. Druhý je nestandardní způsob deklarace proměnné jako absolutní, což znamená, že je umístěna na stejném paměťovém místě jako jiná proměnná nebo na absolutní adrese. Zatímco všechny kompilátory Pascal podporují záznamy variant, pouze některé podporují absolutní proměnné.

Pro účely tohoto příkladu jsou všechny celočíselné typy následující: bajt je 8bitový, slovo je 16bitové a celé číslo je 32bitové.

Následující příklad ukazuje nestandardní absolutní formu:

VAR
    A: Integer;
    B: Array[1..4] of Byte absolute A;
    C: Integer absolute 0;

V prvním příkladu se každý z prvků pole B mapuje na jeden ze specifických bytů proměnné A. V druhém příkladu je proměnná C přiřazena k přesné adrese počítače 0.

V následujícím příkladu má záznam varianty, z nichž některé sdílejí stejné umístění jako ostatní:

TYPE
     TSystemTime = record
       Year, Month, DayOfWeek, Day : word;
       Hour, Minute, Second, MilliSecond: word;
     end;  
     TPerson = RECORD
        FirstName, Lastname: String;
        Birthdate: TSystemTime;
        Case isPregnant: Boolean of 
           true: (DateDue:TSystemTime);
           false: (isPlanningPregnancy: Boolean);
        END;

PL/I

V PL/I pak byl původní termín pro sjednocení buňka , která je stále přijímána jako synonymum pro sjednocení několika kompilátory. Prohlášení o sjednocení je podobné definici struktury, kde prvky na stejné úrovni v rámci prohlášení o sjednocení zabírají stejné úložiště. Prvky sjednocení mohou být libovolné datové typy, včetně struktur a polí. Zde vers_num a vers_bytes zaujímají stejná umístění úložiště.

  1  vers_info         union,
     5 vers_num        fixed binary,
     5 vers_bytes      pic '(2)A';

Alternativou k deklaraci sjednocení je atribut DEFINED, který umožňuje alternativní deklarace úložiště, datové typy základní a definované proměnné se však musí shodovat.

Syntaxe a příklad

C/C ++

V C a C ++ je syntaxe:

union <name>
{
    <datatype>  <1st variable name>;
    <datatype>  <2nd variable name>;
    .
    .
    .
    <datatype>  <nth variable name>;
} <union variable name>;

Struktura může být také členem unie, jak ukazuje následující příklad:

union name1
{
    struct name2
    {  
        int     a;
        float   b;
        char    c;
    } svar;
    int     d;
} uvar;

Tento příklad definuje proměnnou uvarjako sjednocení (označené jako name1), které obsahuje dva členy, strukturu (označenou jako name2) pojmenovanou svar(která zase obsahuje tři členy) a celočíselnou proměnnou pojmenovanou d.

Odbory se mohou vyskytovat v rámci struktur a polí a naopak:

struct
{  
    int flags;
    char *name;
    int utype;
    union {
        int ival;
        float fval;
        char *sval;
    } u;
} symtab[NSYM];

Číslo ival je označováno jako symtab[i].u.ivala první znak řetězce sval buď z *symtab[i].u.svalnebo symtab[i].u.sval[0].

PHP

Typy unie byly zavedeny v PHP 8.0. Hodnoty jsou implicitně „označeny“ typem podle jazyka a lze je načíst pomocí „gettype ()“.

class Example
{
    private int|float $foo;

    public function squareAndAdd(float|int $bar): int|float
    {
        return $bar ** 2 + $this->foo;
    }
}

Krajta

Podpora pro psaní byla zavedena v Pythonu 3.5. Nová syntaxe pro typy sjednocení byla zavedena v Pythonu 3.10.

class Example:
    foo = 0

    def square_and_add(self, bar: int | float) -> int | float:
        return bar ** 2 + self.foo

Strojopis

V jazyce TypeScript jsou podporovány typy odborů. Hodnoty jsou implicitně „označeny“ typem podle jazyka a lze je načíst pomocí „typeof ()“.

function successor(n: number | bigint): number | bigint {
    return ++n
}

Rozdíl mezi unií a strukturou

Union je třída, jejíž všichni členové jsou namapováni na stejnou adresu v rámci svého objektu. Velikost objektu sjednocení je tedy velikost jeho největšího datového člena.

Ve struktuře jsou všechny její datové členy uloženy v souvislých paměťových místech. Velikost objektu struktury je tedy velikost součtu všech jeho datových členů.

Tento zisk v prostorové efektivitě, i když je za určitých okolností cenný, přichází s vysokými náklady na bezpečnost: logika programu musí zajistit, že čte pouze pole, které bylo naposledy napsáno, po všech možných cestách provádění. Výjimkou jsou případy, kdy se pro převod typu používají odbory : v tomto případě se zapíše určité pole a následně načtené pole se záměrně liší.

Jako příklad ilustrující tento bod deklarace

struct foo { int a; float b; }

definuje datový objekt se dvěma členy zabírajícími po sobě jdoucí paměťová místa:

                ┌─────┬─────┐
           foo  │  a  │  b  │
                └─────┴─────┘
                   ↑     ↑
Memory address:  0150  0154

Naproti tomu prohlášení

union bar { int a; float b; }

definuje datový objekt se dvěma členy, kteří zabírají stejné umístění v paměti:

                ┌─────┐
           bar  │  a  │
                │  b  │
                └─────┘
                   ↑
Memory address:  0150

Struktury se používají tam, kde je „objekt“ složen z jiných objektů, jako je bodový objekt skládající se ze dvou celých čísel, z nichž jsou souřadnice xay:

typedef struct {
    int x;           // x and y are separate
    int y;
} tPoint;

Odbory se obvykle používají v situaci, kdy předmětem může být jedna z mnoha věcí, ale pouze jedna najednou, například beztypový úložný systém:

typedef enum { STR, INT } tType;
typedef struct {
    tType typ;          // typ is separate.
    union {
        int ival;       // ival and sval occupy same memory.
        char *sval;
    };
} tVal;

Viz také

Reference

externí odkazy