Typedef - Typedef
typedef je vyhrazené klíčové slovo v programovací jazyky C a C ++. Používá se k vytvoření dalšího názvu (alias) pro další datový typ, ale nevytvoří nový typ[1], s výjimkou nejasného případu a kvalifikovaný typedef typu pole, kde jsou kvalifikátory typedef přeneseny na typ prvku pole[2]. Jako takový se často používá ke zjednodušení syntaxe deklarování komplexu datové struktury skládající se z struktur a typy spojení, ale je stejně běžné při poskytování konkrétních názvů popisných typů pro celočíselné datové typy různých délek.
Syntax
Syntaxe deklarace typedef je:[3]
typedef
prohlášení o typu;
Název nového aliasu typu se řídí stejnou syntaxí jako deklarace jakéhokoli jiného identifikátoru C, tedy v podrobnější podobě:
typedef
definice typu identifikátor
V C standardní knihovna a v POSIX specifikace je často doplněn identifikátor definice definice typu _t
, například v size_t a time_t. Toto se praktikuje v jiných kódovacích systémech, ačkoli POSIX si tuto praxi výslovně vyhrazuje POSIX typy dat.
Příklady
typedef int délka;
Tím se vytvoří typ délka
jako synonymum typu int
.
Použití dokumentace
Deklaraci typedef lze použít jako dokumentaci uvedením významu proměnné v kontextu programování, např. Může zahrnovat vyjádření měrné jednotky nebo počtu. Obecná prohlášení,
int aktuální rychlost;int vysoké skóre;prázdnota gratuluji(int tvé skóre) { -li (tvé skóre > vysoké skóre) { // ... }}
lze vyjádřit prohlášením kontextově specifických typů:
typedef int km_za_hodinu;typedef int bodů;// `km_per_hour` je zde synonymem pro` int`, a tak kompilátor zachází// naše nové proměnné jako celá čísla.km_za_hodinu aktuální rychlost;bodů vysoké skóre;prázdnota gratuluji(bodů tvé skóre) { -li (tvé skóre > vysoké skóre) { // ... }}
Obě části kódu se provádějí shodně. Použití deklarací typedef ve druhém bloku kódu však jasně ukazuje, že tyto dvě proměnné představují stejný datový typ int
, ukládat různá nebo nekompatibilní data. Definice v blahopřát ()
z tvé skóre
označuje programátorovi, že aktuální rychlost
(nebo jakákoli jiná proměnná, která není deklarována jako bodů
) by neměl být předáván jako argument. To by nebylo tak zjevné, kdyby byly obě deklarovány jako proměnné int
datový typ. Indikace však je pouze pro programátora; kompilátor C / C ++ považuje obě proměnné za typ int
a neoznačuje varování nebo chyby ohledně neshod typu pro "nesprávné" typy argumentů pro gratuluji (body your_score)
ve fragmentu kódu níže:
prázdnota foo() { km_za_hodinu km100 = 100; gratuluji(km100);}
Zjednodušení typu
Ke zjednodušení deklarace složeného typu lze použít typedef (struktur, svaz ) nebo ukazatel typ.[4] Například,
struktur MyStruct { int data1; char data2;};
To definuje datový typ struktura MyStruct
. Deklarace proměnné tohoto typu v jazyce C také vyžaduje klíčové slovo struktur
, ale v C ++ to lze vynechat:
struct MyStruct a;
Deklarace typedef vylučuje požadavek na specifikaci struktur
v C. Například prohlášení
typedef struct MyStruct newtype;
se snižuje na:
newtype a;
Deklaraci struktury a typedef lze také zkombinovat do jednoho příkazu:
typedef struktur MyStruct { int data1; char data2;} nový typ;
Nebo jej lze použít následovně:
typedef struktur { int data1; char data2;} nový typ;
v C ++, na rozdíl od C, klíčová slova struktur
, třída
, a výčet
jsou volitelné v deklaracích proměnných, které jsou oddělené od definic, pokud neexistuje dvojznačnost s jiným identifikátorem:
struktur MyStruct X;MyStruct y;
Jako takový, MyStruct
lze použít kdekoli nový typ
může být použito. Opak však není pravdivý; například metody konstruktoru pro MyStruct
nelze pojmenovat nový typ
.
Notoricky známý příklad, kdy dokonce C ++ potřebuje struktur
klíčové slovo je POSIX statní systémové volání který ve svých argumentech používá strukturu se stejným názvem:
int stat(konst char *název souboru, struktur stat *buf){ // ...}
Tady oba C stejně jako C ++ potřebovat struktur
klíčové slovo v definici parametru.
Ukazatele
Typedef může být použit k definování nového typu ukazatele.
typedef int *intptr;intptr ptr;// Stejný jako:// int * ptr;
intptr
je nový alias s typem ukazatele int *
. Definice, intptr ptr;
, definuje proměnnou ptr
s typem int *
. Tak, ptr
je ukazatel, který může ukazovat na proměnnou typu int
.
Použití typedef k definování nového typu ukazatele může někdy vést k nejasnostem. Například:
typedef int *intptr;// Jak cliff, tak allen jsou typu int *.intptr útes, Allen;// 'cliff2' je typu int *, ale 'allen2' je typu int **.intptr útes2, *allen2;// Stejný jako:// intptr cliff2;// intptr * allen2;
Výše, intptr útes, allen;
znamená definování 2 proměnných pomocí int *
typ pro oba. Důvodem je, že typ definovaný typedef je typ, nikoli expanze. Jinými slovy, intptr
, který je int *
typ, zdobí obojí útes
a Allen
. Pro intptr cliff2, * allen2;
, intptr
typ zdobí útes2
a * allen2
. Tak, intptr cliff2, * allen2;
odpovídá 2 samostatným definicím, intptr cliff2;
a intptr * allen2
. intptr * allen2
znamená, že allen2
je ukazatel ukazující na paměť s int *
typ. Krátce, allen2
má typ, int **
.
Struktury a ukazatele struktury
Typedefs může také zjednodušit definice nebo deklarace pro struktura ukazatel typy. Zvaž toto:
struktur Uzel { int data; struktur Uzel *nextptr;};
Pomocí typedef lze výše uvedený kód přepsat takto:
typedef struktur Uzel Uzel;struktur Uzel { int data; Uzel *nextptr;};
V jazyce C lze deklarovat více proměnných stejného typu v jednom příkazu, dokonce i míchání struktury s ukazatelem nebo ukazateli. Pro označení každé proměnné jako ukazatele je však nutné předponu označit hvězdičkou. V následujícím textu to může předpokládat programátor errptr
byl opravdu Uzel *
, ale typografická chyba to znamená errptr
je Uzel
. To může vést k jemným syntaktickým chybám.
struktur Uzel *startptr, *endptr, *Curptr, *předchozí, errptr, *refptr;
Definováním typedef Uzel *
, je zajištěno, že všechny proměnné jsou typy ukazatelů struktury, nebo řekněme, že každá proměnná je a typ ukazatele ukazuje na a typ struktury.
typedef struktur Uzel* NodePtr;NodePtr startptr, endptr, Curptr, předchozí, errptr, refptr;
Ukazatele funkcí
int do_math(plovák arg1, int arg2) { vrátit se arg2;}int call_a_func(int (*call_this)(plovák, int)) { int výstup = call_this(5.5, 7); vrátit se výstup;}int konečný výsledek = call_a_func(&do_math);
Předchozí kód může být přepsán specifikacemi typedef:
typedef int (*MathFunc)(plovák, int);int do_math(plovák arg1, int arg2) { vrátit se arg2;}int call_a_func(MathFunc call_this) { int výstup = call_this(5.5, 7); vrátit se výstup;}int konečný výsledek = call_a_func(&do_math);
Tady, MathFunc
je nový alias pro typ. A MathFunc
je ukazatel na funkci, která vrací celé číslo a jako argumenty bere float následovaný celým číslem.
Když funkce vrací ukazatel funkce, může být bez typedef ještě matoucí. Následuje funkční prototyp funkce signál (3) z FreeBSD:
prázdnota (*signál(int sig, prázdnota (*func)(int)))(int);
Deklarace funkce výše je záhadná, protože jasně neukazuje, co funkce přijímá jako argumenty, ani typ, který vrátí. Začínající programátor může dokonce předpokládat, že funkce přijímá jeden int
jako argument a nevrací nic, ale ve skutečnosti také potřebuje ukazatel funkce a vrací jiný ukazatel funkce. Dá se to napsat čistěji:
typedef prázdnota (*sighandler_t)(int);sighandler_t signál(int sig, sighandler_t func);
Pole
Typedef lze také použít ke zjednodušení definice typů polí. Například,
typedef char arrType[6];arrType přílet = {1, 2, 3, 4, 5, 6};arrType *pArr;// Stejný jako:// char arr [6] = {1, 2, 3, 4, 5, 6};// char (* pArr) [6];
Tady, arrType
je nový alias pro char [6]
type, což je typ pole se 6 prvky. Pro arrType * pArr;
, pArr
je ukazatel ukazující na paměť char [6]
typ.
Zadejte odlitky
Typedef je vytvořen pomocí typu definice syntaxi, ale lze ji použít, jako kdyby byla vytvořena pomocí typu obsazení syntax. (Typ odlévání změní datový typ.) Například v každém řádku za prvním řádkem:
// `funcptr` je ukazatel na funkci, která přebírá` double` a vrací `int`.typedef int (*funcptr)(dvojnásobek);// Platí v C nebo C ++.funcptr X = (funcptr) NULA;// Platí pouze v C ++.funcptr y = funcptr(NULA);funcptr z = static_cast<funcptr>(NULA);
funcptr
se používá na levé straně k deklaraci proměnné a na pravé straně se používá k seslání hodnoty. Typedef tedy mohou používat programátoři, kteří nechtějí přijít na to, jak převést syntaxi definice na syntaxi typu cast.
Bez typedef není obecně možné používat syntaxi definic a syntaxi cast zaměnitelně. Například:
prázdnota *p = NULA;// To je legální.int (*X)(dvojnásobek) = (int (*)(dvojnásobek)) p;// Levá strana není legální.int (*)(dvojnásobek) y = (int (*)(dvojnásobek)) p;// Pravá strana není legální.int (*z)(dvojnásobek) = (int (*p)(dvojnásobek));
Použití v C ++
V jazyce C ++ mohou být názvy typů složité a typedef poskytuje mechanismus k přiřazení jednoduchého názvu typu.
std::vektor<std::pár<std::tětiva, int>> hodnoty;pro (std::vektor<std::pár<std::tětiva, int>>::const_iterator i = hodnoty.začít(); i != hodnoty.konec(); ++i){ std::pár<std::tětiva, int> konst & t = *i; // ...}
a
typedef std::pár<std::tětiva, int> hodnota_t;typedef std::vektor<hodnota_t> hodnoty_t;hodnoty_t hodnoty;pro (hodnoty_t::const_iterator i = hodnoty.začít(); i != hodnoty.konec(); ++i){ hodnota_t konst & t = *i; // ...}
C ++ 11 zavedla možnost vyjádřit typedefs pomocí použitím
namísto typedef
. Například dva výše uvedené typy lze ekvivalentně zapsat jako
použitím hodnota_t = std::pár<std::tětiva, int>;použitím hodnoty_t = std::vektor<hodnota_t>;
Použijte se šablonami
C ++ 03 neposkytuje šablony typedefs. Například mít stringpair
zastupovat std :: pair
pro každý typ T
jeden nemůže použití:
šablona<typename T>typedef std::pár<std::tětiva, T> řetězec<T>; // nefunguje
Pokud je však člověk ochotný to přijmout stringpair
místo stringpair
, pak je možné dosáhnout požadovaného výsledku pomocí typedef v jinak nepoužívané šablonované třídě nebo struktuře:
šablona<typename T>třída řetězec{soukromé: // Zabránit vytvoření instance `stringpair `. řetězec();veřejnost: // Make `stringpair :: type` represent` std :: pair `. typedef std::pár<std::tětiva, T> typ;};// Deklarujte proměnnou typu `std :: pair `. řetězec<int>::typ my_pair_of_string_and_int;
v C ++ 11, šablony typedefs jsou přidány s následující syntaxí, která vyžaduje použitím
spíše než klíčové slovo typedef
klíčové slovo. (Vidět aliasy šablon.)[5]
šablona <typename T>použitím řetězec = std::pár<std::tětiva, T>;// Deklarujte proměnnou typu `std :: pair `. řetězec<int> my_pair_of_string_and_int;
Jiné jazyky
v SystemVerilog, typedef se chová přesně tak, jak se chová v C a C ++.[6]
V mnoha staticky zadaných funkčních jazycích, jako je Haskell, Mirando, OCaml, atd., lze definovat zadejte synonyma, které jsou stejné jako typedefs v C. Příklad v Haskellu:
typ PairOfInts = (Int, Int)
Tento příklad definoval synonymum typu PairOfInts
jako celočíselný typ.
v 7. semeno definice konstantního typu se používá k zavedení synonyma pro typ:
const typ: myVector je celé číslo pole;
v Rychlý, jeden používá typealias
klíčové slovo pro vytvoření typedef:
typealias PairOfInts = (Int, Int)
C# obsahuje funkci, která je podobná typedef nebo použitím
syntaxe C ++.[7][5]
použitím newType = globální::Systém.Runtime.Interop.Maršál;použitím otherType = Výčty.MyEnumType;použitím StringListMap = Systém.Sbírky.Obecný.Slovník<tětiva, Systém.Sbírky.Obecný.Seznam<tětiva>>;
v D klíčové slovo alias
[8] umožňuje vytvářet synonyma typu nebo částečného typu.
struktur Foo(T){}alias FooInt = Foo!int;alias Zábava = int delegát(int);
Obavy z používání
Kernighan a Ritchie uvedli dva důvody pro použití překlepu.[1] Nejprve poskytuje prostředky, díky nimž je program přenosnější nebo snadnější na údržbu. Místo toho, abyste museli měnit typ v každém vzhledu ve zdrojových souborech programu, je třeba změnit pouze jeden příkaz typedef. size_t a ptrdiff_t v
Někteří programátoři se staví proti rozsáhlému používání typedefů. Většina argumentů se soustředí na myšlenku, že typedefs jednoduše skryjí skutečný datový typ proměnné. Například, Greg Kroah-Hartman, a Linuxové jádro hacker a dokumentarista, odrazuje od jejich použití pro cokoli kromě deklarací prototypů funkcí. Tvrdí, že tato praxe nejen zbytečně zamlžuje kód, ale může také způsobit, že programátoři omylem zneužijí velké struktury a budou je považovat za jednoduché typy.[9]
Viz také
Reference
- ^ A b Kernighan, Brain W.; Ritchie, Dennis M. (1988). Programovací jazyk C. (2. vyd.). Englewood Cliffs, New Jersey .: Prentice Hall. p.147. ISBN 0-13-110362-8. Citováno 18. června 2016.
C poskytuje zařízení zvané typedef pro vytváření nových názvů datových typů. … Je třeba zdůraznit, že deklarace typedef nevytváří v žádném smyslu nový typ; pouze přidá nový název pro nějaký existující typ.
- ^ "kvalifikátor typu const". cppreference.com. Citováno 2020-10-20.
- ^ "typedef specifikátor". cppreference.com. Citováno 18. června 2016.
- ^ Deitel, Paul J .; Deitel, H. M. (2007). C jak programovat (5. vydání). Upper Saddle River, N.J .: Pearson Prentice Hall. ISBN 9780132404167. Citováno 12. září 2012.
Názvy typů struktur jsou často definovány pomocí typedef k vytvoření kratších názvů typů.
- ^ A b „Type alias, alias template (since C ++ 11) - cppreference.com“. en.cppreference.com. Citováno 2018-09-25.
- ^ Tala, Deepak Kumar. "Datové typy SystemVerilog, část V". www.asic-world.com. ASIC Svět. Citováno 25. září 2018.
- ^ http://msdn.microsoft.com/en-us/library/aa664765(VS.71).aspx
- ^ "Deklarace - programovací jazyk D". dlang.org. Citováno 2017-05-28.
- ^ Kroah-Hartman, Greg (2002-07-01). "Správný styl kódování jádra Linuxu". Linux Journal. Citováno 2007-09-23.
Použití definice typu skryje pouze skutečný typ proměnné.