Sök…


Introduktion

typedef mekanismen gör det möjligt att skapa alias för andra typer. Det skapar inte nya typer. Människor använder ofta typedef att förbättra portabiliteten för kod, för att ge alias till struktur- eller facktyper eller för att skapa alias för funktionstyp (eller funktionspekare).

I C-standarden klassificeras typedef som en "lagringsklass" för bekvämlighet; det inträffar syntaktiskt där lagringsklasser som static eller extern kan visas.

Syntax

  • typedef existensnamn aliasnamn;

Anmärkningar


Nackdelar med Typedef

typedef kan leda till förorening av namnområdet i stora C-program.

Nackdelar med Typedef-strukturer

Dessutom är typedef d strukturer utan etikettnamn en viktig orsak till onödigt påläggning av beställningsrelationer mellan sidfiler.

Överväga:

#ifndef FOO_H
#define FOO_H 1

#define FOO_DEF (0xDEADBABE)

struct bar; /* forward declaration, defined in bar.h*/

struct foo {
    struct bar *bar;
};

#endif

Med en sådan definition, utan att använda typedefs , är det möjligt för en sammanställningsenhet att inkludera foo.h att få FOO_DEF definitionen. Om den inte försöker ta bort bar i foo strukturen kommer det inte att behöva inkludera filen bar.h

Typedef vs #define

#define är ett C-förprocessordirektiv som också används för att definiera alias för olika datatyper som liknar typedef men med följande skillnader:

  • typedef är begränsat till att ge symboliska namn på typer endast där #define kan användas för att definiera alias för värden också.

  • typedef tolkning utförs av kompilatorn medan #define uttalanden behandlas av #define .

  • Observera att #define cptr char * följt av cptr a, b; gör inte samma sak som typedef char *cptr; följt av cptr a, b; . Med #define är b en vanlig char variabel, men det är också en pekare med typedef .

Typedef för strukturer och fackföreningar

Du kan ge alias namn till en struct :

typedef struct Person {
    char name[32];
    int age;
} Person;

Person person;

Jämfört med det traditionella sättet att deklarera strukturer, behöver inte programmerare ha struct varje gång de förklarar en instans av den strukturen.

Observera att namnet Person (i motsats till struct Person ) inte definieras förrän det sista semikolonet. För länkade listor och trädstrukturer som måste innehålla en pekare till samma strukturtyp måste du således använda antingen:

typedef struct Person {
    char name[32];
    int age;
    struct Person *next;
} Person;

eller:

typedef struct Person Person;

struct Person {
    char name[32];
    int age;
    Person *next;
};

Användningen av en typedef för en union typ är mycket lika.

typedef union Float Float;

union Float
{
    float f;
    char  b[sizeof(float)];
};

En struktur som liknar denna kan användas för att analysera byte som utgör ett float .

Enkla användningar av Typedef

För att ge korta namn på en datatyp

Istället för:

long long int foo;
struct mystructure object;

man kan använda

/* write once */
typedef long long ll;
typedef struct mystructure mystruct;

/* use whenever needed */
ll foo;
mystruct object;

Detta minskar mängden maskinskrivning som behövs om typen används många gånger i programmet.

Förbättra portabiliteten

Datatypens attribut varierar mellan olika arkitekturer. Till exempel kan en int vara en 2-byte-typ i en implementering och en 4-byte-typ i en annan. Anta att ett program måste använda en 4-bytyp för att köra korrekt.

I en implementering, låt storleken på int vara 2 byte och den på long vara 4 byte. I en annan, låt storleken på int vara 4 byte och den på long vara 8 byte. Om programmet skrivs med den andra implementeringen,

/* program expecting a 4 byte integer */
int foo; /* need to hold 4 bytes to work */
/* some code involving many more ints */

För att programmet ska köras i den första implementeringen måste alla int deklarationer ändras till long .

/* program now needs long */
long foo; /*need to hold 4 bytes to work */
/* some code involving many more longs - lot to be changed */

För att undvika detta kan man använda typedef

/* program expecting a 4 byte integer */
typedef int myint; /* need to declare once - only one line to modify if needed */
myint foo; /* need to hold 4 bytes to work */
/* some code involving many more myints */

Sedan typedef bara typedef varje gång istället för att granska hela programmet.

C99

<stdint.h> och den relaterade <inttypes.h> rubriken definierar standardtypnamn (med typedef ) för heltal i olika storlekar, och dessa namn är ofta det bästa valet i modern kod som behöver heltal med fast storlek. Till exempel är uint8_t en osignerad 8-bitars heltalstyp; int64_t är en signerad 64-bitars heltalstyp. Typen uintptr_t är en osignerad heltalstyp som är tillräckligt stor för att hålla någon pekare att objektera. Dessa typer är teoretiskt frivilliga - men det är sällsynt att de inte är tillgängliga. Det finns varianter som uint_least16_t (den minsta osignerade heltalstypen med minst 16 bitar) och int_fast32_t (den snabbast signerade heltalstypen med minst 32 bitar). intmax_t och uintmax_t är också de största heltalstyperna som stöds av implementeringen. Dessa typer är obligatoriska.

För att ange en användning eller för att förbättra läsbarheten

Om en uppsättning data har ett särskilt syfte kan man använda typedef att ge det ett meningsfullt namn. Dessutom, om egenskapen till data ändras så att bastypen måste ändras, måste bara typedef uttalandet ändras i stället för att undersöka hela programmet.

Typedef för funktionspekare

Vi kan använda typedef att förenkla användningen av funktionspekare. Föreställ dig att vi har några funktioner, alla med samma signatur, som använder deras argument för att skriva ut något på olika sätt:

#include<stdio.h>

void print_to_n(int n)
{
    for (int i = 1; i <= n; ++i)
        printf("%d\n", i);
}

void print_n(int n)
{
    printf("%d\n, n);
}

Nu kan vi använda en typedef att skapa en namngiven funktionspekartyp som heter skrivare:

typedef void (*printer_t)(int);

Detta skapar en typ med namnet printer_t för en pekare till en funktion som tar ett enda int argument och returnerar ingenting, vilket matchar signaturen för de funktioner vi har ovan. För att använda den skapar vi en variabel av den skapade typen och tilldelar den en pekare till en av funktionerna i fråga:

printer_t p = &print_to_n;
void (*p)(int) = &print_to_n; // This would be required without the type

För att anropa den funktion som funktionspekvariabeln pekar på:

p(5);           // Prints 1 2 3 4 5 on separate lines
(*p)(5);        // So does this

Således tillåter typedef en enklare syntax när man hanterar funktionspekare. Detta blir tydligare när funktionspekare används i mer komplexa situationer, till exempel argument för funktioner.

Om du använder en funktion som tar en funktionspekare som en parameter utan en funktionspekertyp definierad skulle funktionsdefinitionen vara,

void foo (void (*printer)(int), int y){
    //code
    printer(y);
    //code
}

Men med typedef är det:

void foo (printer_t printer, int y){
    //code
    printer(y);
    //code
}

På samma sätt kan funktioner returnera funktionspekare och återigen kan användningen av en typedef göra syntaxen enklare när du gör det.

Ett klassiskt exempel är signal från <signal.h> . Förklaringen för den (från C-standarden) är:

void (*signal(int sig, void (*func)(int)))(int);

Det är en funktion som tar två argument - en int och en pekare till en funktion som tar en int som ett argument och returnerar ingenting - och som returnerar en pekare för att fungera som dess andra argument.

Om vi definierade en typ SigCatcher som ett alias för pekaren att fungera:

typedef void (*SigCatcher)(int);

då kan vi deklarera signal() med:

SigCatcher signal(int sig, SigCatcher func);

Sammantaget är detta lättare att förstå (även om C-standarden inte valde att definiera en typ för att göra jobbet). signal tar två argument, en int och en SigCatcher , och den returnerar en SigCatcher - där en SigCatcher är en pekare till en funktion som tar ett int argument och returnerar ingenting.

Även om att använda typedef namn för pekaren för att fungera typer underlättar livet, kan det också leda till förvirring för andra som kommer att behålla din kod senare, så använd med försiktighet och korrekt dokumentation. Se även Funktionspekare .



Modified text is an extract of the original Stack Overflow Documentation
Licensierat under CC BY-SA 3.0
Inte anslutet till Stack Overflow