Markør (computerprogrammering) - Pointer (computer programming)

Jeg betragter opgaveanvisninger og markørvariabler som en af ​​datalogiens "mest værdifulde skatte."

Donald Knuth , Structured Programming, med go to Statements

Markør a, der peger på hukommelsesadressen, der er forbundet med variabel b . I dette diagram bruger computearkitekturen det samme adresserum og data primitive for både pointers og non-pointers; dette behov bør ikke være tilfældet.

Inden for datalogi er en markør et objekt på mange programmeringssprog, der gemmer en hukommelsesadresse . Dette kan være værdien af ​​en anden værdi i computerens hukommelse eller i nogle tilfælde værdien af hukommelseskortet hardware . En markør refererer til et sted i hukommelsen, og opnåelse af værdien, der er gemt på det sted, er kendt som dereferencing af markøren. Som en analogi kunne et sidetal i en bogs indeks betragtes som en markør til den tilsvarende side; dereferencing af en sådan markør ville blive gjort ved at bladre til siden med det angivne sidetal og læse teksten, der findes på den side. Det faktiske format og indholdet af en markørvariabel afhænger af den underliggende computerarkitektur .

Ved hjælp af pointere forbedrer ydeevnen for gentagne operationer, ligesom gennemkører Iterable data strukturer (fx strygere , opslagstabeller , kontrol borde og træ strukturer). Især er det ofte meget billigere i tid og rum at kopiere og afvise pointer, end det er at kopiere og få adgang til de data, som pointerne peger på.

Pegere bruges også til at holde adresserne på indgangspunkter for kaldte underrutiner i procedureprogrammering og til kørselstidslinkning til dynamiske linkbiblioteker (DLL'er) . I objektorienteret programmering , pegepinde til funktioner anvendes til binding metoder , ofte ved hjælp af virtuelle metode tabeller .

En pointer er en enkel, mere konkrete gennemførelse af den mere abstrakte henvisning datatype . Flere sprog, især sprog på lavt niveau , understøtter en vis markør, selvom nogle har flere restriktioner for deres brug end andre. Selvom "pointer" er blevet brugt til at henvise til referencer generelt, gælder det mere korrekt for datastrukturer, hvis grænseflade eksplicit gør det muligt at manipulere markøren (aritmetisk via pointer aritmetic ) som en hukommelsesadresse, i modsætning til enmagisk cookieellerfunktion,der ikke tillader sådan. Fordi pegepinde giver både beskyttet og ubeskyttet adgang til hukommelsesadresser, er der risici forbundet med at bruge dem, især i sidstnævnte tilfælde. Primitive pointer gemmes ofte i et format, der ligner ethelt tal; et forsøg på at aflæse eller "slå op" en sådan markør, hvis værdi ikke er en gyldig hukommelsesadresse, kan imidlertid få et program til atgå ned(eller indeholde ugyldige data). For at afhjælpe dette potentielle problem, som et spørgsmål omtypen sikkerhed, er pejlemærker betragtes som en særskilt form parametriseres af den type data, de peger på, selv om den underliggende repræsentation er et heltal. Der kan også træffes andre foranstaltninger (f.eks.Valideringoggrænsekontrol) for at kontrollere, at markørvariablen indeholder en værdi, der både er en gyldig hukommelsesadresse og inden for det numeriske område, som processoren kan adressere.

Historie

I 1955 sovjetiske datalog Kateryna Jusjtjenko opfandt programmeringssproget Adresse , der gjorde muligt indirekte adressering og adresser på den højeste rang - analogt med pointere. Dette sprog blev meget udbredt på Sovjetunionens computere. Det var imidlertid ukendt uden for Sovjetunionen, og normalt krediteres Harold Lawson med opfindelsen i 1964 af markøren. I 2000 blev Lawson overrakt Computer Pioneer Award af IEEE "[f] eller opfandt markørvariablen og introducerede dette koncept i PL/I og gav således for første gang mulighed for fleksibelt at behandle sammenkædede lister i generelle formål sprog på højt niveau ". Hans grundlæggende papir om begreberne optrådte i juni 1967 -udgaven af ​​CACM med titlen: PL/I List Processing. Ifølge Oxford English Dictionary , det ord pointer først dukkede op i print som en stak pointer i en teknisk notat fra System Development Corporation .

Formel beskrivelse

Inden for datalogi er en pointer en slags reference .

En dataprimitiv (eller bare primitiv ) er et hvilket som helst datum, der kan læses fra eller skrives til computerhukommelse ved hjælp af en hukommelsesadgang (for eksempel er både en byte og et ord primitiver).

Et dataaggregat (eller bare aggregat ) er en gruppe primitiver, der er logisk sammenhængende i hukommelsen, og som ses kollektivt som et henføringspunkt (for eksempel kan et aggregat være 3 logisk sammenhængende bytes, hvis værdier repræsenterer de 3 koordinater for et punkt i rummet). Når et aggregat helt er sammensat af den samme type primitiv, kan aggregatet kaldes en array ; på en måde er et multi-byte- ord primitivt en række bytes, og nogle programmer bruger ord på denne måde.

I forbindelse med disse definitioner er en byte den mindste primitive; hver hukommelsesadresse angiver en anden byte. Hukommelsesadressen for et startpunkts byte betragtes som hukommelsesadressen (eller basishukommelsesadressen ) for hele nulpunktet.

En hukommelsesmarkør (eller bare markør ) er en primitiv, hvis værdi er beregnet til at blive brugt som en hukommelsesadresse; det siges, at en markør peger på en hukommelsesadresse . Det siges også, at en markør peger på et nulpunkt [i hukommelsen], når markørens værdi er nulpunktets hukommelsesadresse.

Mere generelt er en markør en slags reference , og det siges, at en markør refererer til et datum, der er gemt et sted i hukommelsen ; at opnå dette datum er at afskrive markøren . Funktionen, der adskiller pointer fra andre former for reference, er, at en pointeres værdi er beregnet til at blive fortolket som en hukommelsesadresse, hvilket er et temmelig lavt niveau-koncept.

Referencer tjener som et indirekte niveau: En pointerværdi bestemmer hvilken hukommelsesadresse (det vil sige hvilket datum) der skal bruges i en beregning. Fordi indirektion er et grundlæggende aspekt af algoritmer, udtrykkes pointer ofte som en grundlæggende datatype i programmeringssprog ; i statisk (eller stærkt ) indtastede programmeringssprog, bestemmer typen af en markør typen af ​​nulpunktet, som markøren peger på.

Arkitektoniske rødder

Pegere er en meget tynd abstraktion oven på adresseringskapaciteterne fra de fleste moderne arkitekturer . I den simpleste skema, en adresse eller et numerisk indeks , der er tildelt hver enhed af hukommelse i systemet, hvor enheden er typisk enten en byte eller et ord - afhængigt af, om arkitekturen er byte-adresserbare eller word-adresserbare - effektivt omdanne hele hukommelsen til et meget stort array . Systemet ville derefter også tilvejebringe en operation til at hente værdien, der er gemt i hukommelsesenheden på en given adresse (normalt ved hjælp af maskinens generelle formålsregistre ).

I det sædvanlige tilfælde er en markør stor nok til at indeholde flere adresser, end der er hukommelsesenheder i systemet. Dette introducerer muligheden for, at et program kan forsøge at få adgang til en adresse, der ikke svarer til nogen hukommelsesenhed, enten fordi der ikke er installeret nok hukommelse (dvs. uden for rækkevidde af tilgængelig hukommelse) eller arkitekturen ikke understøtter sådanne adresser. Det første tilfælde kan på visse platforme som f.eks. Intel x86 -arkitekturen kaldes en segmenteringsfejl (segfault). Det andet tilfælde er muligt i den nuværende implementering af AMD64 , hvor pointere er 64 bit lange og adresser kun strækker sig til 48 bit. Pegere skal være i overensstemmelse med visse regler (kanoniske adresser), så hvis en ikke-kanonisk markør aflæses, rejser processoren en generel beskyttelsesfejl .

På den anden side har nogle systemer flere hukommelsesenheder, end der er adresser. I dette tilfælde anvendes et mere komplekst skema, såsom hukommelsessegmentering eller personsøgning, til at bruge forskellige dele af hukommelsen på forskellige tidspunkter. De sidste inkarnationer af x86-arkitekturen understøtter op til 36 bits fysiske hukommelsesadresser, som blev kortlagt til det 32-bit lineære adresserum via PAE- personsøgningsmekanismen. Således er der kun adgang til 1/16 af den mulige samlede hukommelse ad gangen. Et andet eksempel i den samme computerfamilie var 16-bit beskyttet tilstand af 80286- processoren, som, selvom den kun understøtter 16 MB fysisk hukommelse, kunne få adgang til op til 1 GB virtuel hukommelse, men kombinationen af ​​16-bit adresse og segment registre gjorde adgang til mere end 64 KB i en datastruktur besværlig.

For at give en ensartet grænseflade giver nogle arkitekturer hukommelseskortede I/O , som gør det muligt for nogle adresser at henvise til hukommelsesenheder, mens andre refererer til enhedsregistre for andre enheder i computeren. Der er analoge begreber som filforskydninger, matrixindeks og eksterne objektreferencer, der tjener nogle af de samme formål som adresser til andre typer objekter.

Anvendelser

Pegere understøttes direkte uden begrænsninger på sprog som PL/I , C , C ++ , Pascal , FreeBASIC og implicit på de fleste samlingssprog . De bruges primært til at konstruere referencer , som igen er grundlæggende for at konstruere næsten alle datastrukturer samt for at videregive data mellem forskellige dele af et program.

I funktionelle programmeringssprog, der er stærkt afhængige af lister, administreres datareferencer abstrakt ved hjælp af primitive konstruktioner som ulemper og de tilsvarende elementer bil og cdr , som kan betragtes som specialiserede tips til den første og anden komponent i en cons-celle. Dette giver anledning til noget af den idiomatiske "smag" af funktionel programmering. Ved at strukturere data i sådanne cons-lister letter disse sprog rekursive midler til opbygning og behandling af data-for eksempel ved rekursivt at få adgang til hoved- og haleelementerne på lister over lister; fx "at tage bilen fra cdr'en på cdr". I modsætning hertil letter hukommelsesstyring baseret på pointer -dereferencing i en vis tilnærmelse til en række hukommelsesadresser at behandle variabler som slots, hvor data kan tildeles imperativt .

Ved behandling af arrays involverer den kritiske opslagsoperation typisk et trin kaldet adresseberegning, der involverer konstruktion af en markør til det ønskede dataelement i arrayet. I andre datastrukturer, f.eks. Sammenkædede lister , bruges pointer som referencer til eksplicit at knytte et stykke af strukturen til et andet.

Pegere bruges til at videregive parametre ved reference. Dette er nyttigt, hvis programmøren ønsker, at en funktions ændringer af en parameter skal være synlig for funktionens opkald. Dette er også nyttigt til at returnere flere værdier fra en funktion.

Pegere kan også bruges til at allokere og fordele dynamiske variabler og arrays i hukommelsen. Da en variabel ofte vil blive overflødig, efter at den har tjent sit formål, er det spild af hukommelse at beholde den, og derfor er det god praksis at fordele den (ved hjælp af den originale markørreference), når den ikke længere er nødvendig. Undladelse af at gøre dette kan resultere i en hukommelseslækage (hvis ledig hukommelse gradvist eller i alvorlige tilfælde hurtigt falder på grund af en ophobning af mange redundante hukommelsesblokke).

C -tip

Den grundlæggende syntaks for at definere en markør er:

int *ptr;

Dette erklærer ptrsom identifikator for et objekt af følgende type:

  • markør, der peger på et objekt af typen int

Dette er normalt angivet mere kortfattet som " ptrer en fingerpeg til int."

Fordi C -sproget ikke angiver en implicit initialisering for objekter med automatisk lagringsvarighed, bør man ofte passe på, at den adresse, som ptrpunkterne er gyldige til; derfor foreslås det undertiden, at en markør eksplicit initialiseres til nulmarkørværdien , som traditionelt er specificeret i C med den standardiserede makro NULL:

int *ptr = NULL;

Dereferencing af en nullmarkør i C producerer udefineret adfærd , hvilket kan være katastrofalt. Imidlertid stopper de fleste implementeringer simpelthen udførelsen af ​​det pågældende program, normalt med en segmenteringsfejl .

Imidlertid kan initialisering af pointer unødigt hindre programanalyse og derved skjule fejl.

Under alle omstændigheder, når en markør er blevet erklæret, er det næste logiske trin, at den peger på noget:

int a = 5;
int *ptr = NULL;

ptr = &a;

Dette tildeler værdien af ​​adressen atil ptr. For eksempel, hvis den aer gemt på en hukommelsesposition på 0x8130, vil værdien på ptrvære 0x8130 efter tildelingen. For at afvige markøren bruges en stjerne igen:

*ptr = 8;

Dette betyder at tage indholdet af ptr(som er 0x8130), "lokalisere" den adresse i hukommelsen og indstille dens værdi til 8. Hvis ader senere åbnes igen, vil dens nye værdi være 8.

Dette eksempel kan være tydeligere, hvis hukommelsen undersøges direkte. Antag at aer placeret på adressen 0x8130 i hukommelsen og ptrpå 0x8134; antag også, at dette er en 32-bit maskine, så en int er 32-bit bred. Det følgende er, hvad der ville være i hukommelsen, når følgende kodestykke er udført:

int a = 5;
int *ptr = NULL;
Adresse Indhold
0x8130 0x00000005
0x8134 0x00000000

(NULL -markøren vist her er 0x00000000.) Ved at tildele adressen atil ptr:

 ptr = &a;

giver følgende hukommelsesværdier:

Adresse Indhold
0x8130 0x00000005
0x8134 0x00008130

Derefter ved dereferencing ptrved kodning:

 *ptr = 8;

computeren vil tage indholdet af ptr(som er 0x8130), 'lokalisere' den adresse og tildele 8 til den placering, hvilket giver følgende hukommelse:

Adresse Indhold
0x8130 0x00000008
0x8134 0x00008130

Det er klart, at adgang avil give værdien 8, fordi den tidligere instruktion ændrede indholdet af avia markøren ptr.

Brug i datastrukturer

Når du opretter datastrukturer som lister , køer og træer, er det nødvendigt at have tip til at styre, hvordan strukturen implementeres og kontrolleres. Typiske eksempler på pointere er start- pointere, endelige pointere og stak pointere. Disse pointer kan enten være absolutte (den faktiske fysiske adresse eller en virtuel adresse i virtuel hukommelse ) eller relativ (en forskydning fra en absolut startadresse ("base"), der typisk bruger færre bits end en fuld adresse, men normalt vil kræve en ekstra aritmetisk handling at løse).

Relative adresser er en form for manuel segmentering af hukommelse og deler mange af dens fordele og ulemper. Et to-byte offset, der indeholder et 16-bit, usigneret heltal, kan bruges til at tilvejebringe relativ adressering for op til 64 KiB (2 16 bytes) af en datastruktur. Dette kan let udvides til 128, 256 eller 512 KiB, hvis adressen, der peges på, er tvunget til at blive justeret på en grænse for et halvt ord, et ord eller et dobbelt ord (men kræver en yderligere "skift til venstre" bitvis betjening- ved 1, 2 eller 3 bit - for at justere forskydningen med en faktor 2, 4 eller 8, før den tilføjes til basisadressen). Generelt er sådanne ordninger imidlertid mange problemer, og for nemheds skyld foretrækkes absolutte adresser (og derunder et fladt adresserum ).

En one -byte offset, såsom den hexadecimale ASCII -værdi for et tegn (f.eks. X'29 ') kan bruges til at pege på en alternativ heltalværdi (eller indeks) i en matrix (f.eks. X'01'). På denne måde kan tegn meget effektivt oversættes fra ' rådata ' til et brugbart sekventielt indeks og derefter til en absolut adresse uden opslagstabel .

C -arrays

I C er matrixindeksering formelt defineret i form af pegearitmetik; det vil sige, at sprogspecifikationen kræver, at array[i]det svarer til *(array + i). I C kan arrays således betragtes som pointer til på hinanden følgende områder af hukommelse (uden huller), og syntaksen for adgang til arrays er identisk med den, der kan bruges til at aflæse pointer. For eksempel kan en matrix arraydeklareres og bruges på følgende måde:

int array[5];      /* Declares 5 contiguous integers */
int *ptr = array;  /* Arrays can be used as pointers */
ptr[0] = 1;        /* Pointers can be indexed with array syntax */
*(array + 1) = 2;  /* Arrays can be dereferenced with pointer syntax */
*(1 + array) = 2;  /* Pointer addition is commutative */
array[2] = 4;      /* Subscript operator is commutative */

Dette tildeler en blok med fem heltal og navngiver blokken array, der fungerer som en markør til blokken. En anden almindelig brug af pointers er at pege på dynamisk allokeret hukommelse fra malloc, som returnerer en på hinanden følgende blok af hukommelse på ikke mindre end den ønskede størrelse, der kan bruges som en array.

Mens de fleste operatører på arrays og pointer er ækvivalente, er resultatet af sizeofoperatøren forskelligt. I dette eksempel sizeof(array)evalueres til 5*sizeof(int)(størrelsen af ​​arrayet), mens sizeof(ptr)det evalueres til sizeof(int*)størrelsen på selve markøren.

Standardværdier for et array kan erklæres som:

int array[5] = {2, 4, 3, 1, 5};

Hvis den arrayer placeret i hukommelsen fra adresse 0x1000 på en 32-bit lille endian- maskine, indeholder hukommelsen følgende (værdier er i hexadecimal , som adresserne):

0 1 2 3
1000 2 0 0 0
1004 4 0 0 0
1008 3 0 0 0
100C 1 0 0 0
1010 5 0 0 0

Her repræsenteres fem heltal: 2, 4, 3, 1 og 5. Disse fem heltal optager 32 bit (4 bytes) hver med den mindst signifikante byte gemt først (dette er en lille-endian CPU-arkitektur ) og gemmes i rækkefølge fra adresse 0x1000.

Syntaksen for C med pointers er:

  • array betyder 0x1000;
  • array + 1betyder 0x1004: "+ 1" betyder at tilføje størrelsen på 1 int, som er 4 bytes;
  • *arraybetyder at nedlægge indholdet af array. I betragtning af indholdet som en hukommelsesadresse (0x1000), skal du slå værdien op på det sted (0x0002);
  • array[i]betyder elementnummer i, 0-baseret, arrayhvoraf det oversættes til *(array + i).

Det sidste eksempel er, hvordan du får adgang til indholdet af array. Bryde det ned:

  • array + ier hukommelsesplaceringen for (i) th element af array, der starter ved i = 0;
  • *(array + i) tager den hukommelsesadresse og aflæser den for at få adgang til værdien.

C linket liste

Nedenfor er en eksempeldefinition af en linket liste i C.

/* the empty linked list is represented by NULL
 * or some other sentinel value */
#define EMPTY_LIST  NULL

struct link {
    void        *data;  /* data of this link */
    struct link *next;  /* next link; EMPTY_LIST if there is none */
};

Denne pointer-rekursive definition er i det væsentlige den samme som reference-rekursiv definition fra Haskell programmeringssprog :

 data Link a = Nil
             | Cons a (Link a)

Niler den tomme liste, og Cons a (Link a)er en ulempe af typen amed et andet link også af typen a.

Definitionen med referencer er dog typekontrolleret og bruger ikke potentielt forvirrende signalværdier. Af denne grund behandles datastrukturer i C normalt via indpakningsfunktioner , som omhyggeligt kontrolleres for rigtighed.

Pass-by-adresse ved hjælp af pointer

Pegere kan bruges til at videregive variabler efter deres adresse, så deres værdi kan ændres. Overvej f.eks. Følgende C -kode:

/* a copy of the int n can be changed within the function without affecting the calling code */
void passByValue(int n) {
    n = 12;
}

/* a pointer m is passed instead. No copy of the value pointed to by m is created */
void passByAddress(int *m) {
    *m = 14;
}

int main(void) {
    int x = 3;

    /* pass a copy of x's value as the argument */
    passByValue(x);
    // the value was changed inside the function, but x is still 3 from here on

    /* pass x's address as the argument */
    passByAddress(&x);
    // x was actually changed by the function and is now equal to 14 here

    return 0;
}

Dynamisk hukommelsestildeling

I nogle programmer afhænger den nødvendige hukommelse af, hvad brugeren kan indtaste. I sådanne tilfælde skal programmøren tildele dynamisk hukommelse. Dette gøres ved at allokere hukommelse på bunken frem for på stakken , hvor variabler normalt gemmes (variabler kan også gemmes i CPU -registre, men det er en anden sag). Dynamisk hukommelsestildeling kan kun foretages via pointer, og navne (som med almindelige variabler) kan ikke angives.

Pegere bruges til at gemme og administrere adresserne på dynamisk tildelte hukommelsesblokke. Sådanne blokke bruges til at gemme dataobjekter eller arrays af objekter. De fleste strukturerede og objektorienterede sprog giver et hukommelsesområde, kaldet bunken eller frilageret , hvorfra objekter dynamisk tildeles.

Eksemplet C -kode nedenfor illustrerer, hvordan strukturobjekter tildeles dynamisk og refereres til. Den standard C biblioteket tilvejebringer funktionen malloc()til allokering hukommelsesblokke fra dyngen. Det tager størrelsen på et objekt at allokere som en parameter og returnerer en markør til en nyligt tildelt hukommelsesblok, der er egnet til lagring af objektet, eller den returnerer en nullmarkør, hvis tildelingen mislykkedes.

/* Parts inventory item */
struct Item {
    int         id;     /* Part number */
    char *      name;   /* Part name   */
    float       cost;   /* Cost        */
};

/* Allocate and initialize a new Item object */
struct Item * make_item(const char *name) {
    struct Item * item;

    /* Allocate a block of memory for a new Item object */
    item = malloc(sizeof(struct Item));
    if (item == NULL)
        return NULL;

    /* Initialize the members of the new Item */
    memset(item, 0, sizeof(struct Item));
    item->id =   -1;
    item->name = NULL;
    item->cost = 0.0;

    /* Save a copy of the name in the new Item */
    item->name = malloc(strlen(name) + 1);
    if (item->name == NULL) {
        free(item);
        return NULL;
    }
    strcpy(item->name, name);

    /* Return the newly created Item object */
    return item;
}

Nedenstående kode illustrerer, hvordan hukommelsesobjekter dynamisk fordeles, dvs. returneres til bunken eller den frie lager. Standard C -biblioteket giver funktionen free()til at deallokere en tidligere tildelt hukommelsesblok og returnere den tilbage til bunken.

/* Deallocate an Item object */
void destroy_item(struct Item *item) {
    /* Check for a null object pointer */
    if (item == NULL)
        return;

    /* Deallocate the name string saved within the Item */
    if (item->name != NULL) {
        free(item->name);
        item->name = NULL;
    }

    /* Deallocate the Item object itself */
    free(item);
}

Hukommelseskortet hardware

På nogle computerarkitekturer kan pointer bruges til direkte at manipulere hukommelse eller hukommelseskortede enheder.

Tildeling af adresser til pointers er et uvurderligt værktøj ved programmering af mikrokontrollere . Nedenfor er et enkelt eksempel, der erklærer en markør af typen int og initialiserer den til en hexadecimal adresse i dette eksempel konstanten 0x7FFF:

int *hardware_address = (int *)0x7FFF;

I midten af ​​80'erne var det langsomt at bruge BIOS til at få adgang til videofunktionerne på pc'er. Applikationer, der var skærmintensive, bruges typisk til at få adgang til CGA -videohukommelse direkte ved at caste den hexadecimale konstant 0xB8000 til en markør til en matrix med 80 usignerede 16-bit int-værdier. Hver værdi bestod af en ASCII -kode i den lave byte og en farve i den høje byte. For at sætte bogstavet 'A' i række 5, kolonne 2 i lys hvid på blå, ville man således skrive kode som følgende:

#define VID ((unsigned short (*)[80])0xB8000)

void foo(void) {
    VID[4][1] = 0x1F00 | 'A';
}

Brug i kontroltabeller

Kontroltabeller , der bruges til at styre programforløb, gør normalt meget brug af pointer. Pegerne, der normalt er integreret i en tabelpost, kan f.eks. Bruges til at holde indgangspunkterne til underrutiner, der skal udføres, baseret på visse betingelser defineret i den samme tabelpost. Pegerne kan imidlertid simpelthen indeksere andre separate, men tilknyttede tabeller, der omfatter en række af de faktiske adresser eller selve adresserne (afhængigt af de tilgængelige programmeringssprogskonstruktioner). De kan også bruges til at pege på tidligere tabelposter (som i loop -behandling) eller fremad for at springe nogle tabelposter over (som i en switch eller "tidlig" exit fra en loop). Til sidstnævnte formål kan "pointeren" simpelthen være selve tabelindtastningsnummeret og kan omdannes til en faktisk adresse ved simpel aritmetik.

Skrev tip og støbning

På mange sprog har pointer den yderligere begrænsning, at objektet, de peger på, har en bestemt type . For eksempel kan en markør erklæres at pege på et helt tal ; sproget vil derefter forsøge at forhindre programmøren i at pege det på objekter, der ikke er heltal, f.eks. floating-point-tal , hvilket eliminerer nogle fejl.

For eksempel i C

int *money;
char *bags;

moneyville være en heltalsmarkør og bagsville være en char pointer. Det følgende ville give en kompilatoradvarsel om "tildeling fra inkompatibel pointertype" under GCC

bags = money;

fordi moneyog bagsblev erklæret med forskellige typer. For at undertrykke compiler -advarslen skal det gøres eksplicit, at du virkelig ønsker at lave opgaven ved at skrive den

bags = (char *)money;

som siger at kaste heltalemarkøren moneytil en char pointer og tildele til bags.

Et 2005 -udkast til C -standarden kræver, at støbning af en markør, der stammer fra en type til en af ​​en anden, skal opretholde justeringsnøjagtigheden for begge typer (6.3.2.3 Pointers, par. 7):

char *external_buffer = "abcdef";
int *internal_data;

internal_data = (int *)external_buffer;  // UNDEFINED BEHAVIOUR if "the resulting pointer
                                         // is not correctly aligned"

På sprog, der tillader pointer -aritmetik, tager aritmetic on pointers hensyn til typens størrelse. For eksempel vil tilføjelse af et helt tal til en markør frembringe en anden markør, der peger på en adresse, der er højere med det antal gange størrelsen på typen. Dette giver os mulighed for let at beregne adressen på elementer af en matrix af en given type, som det blev vist i C -arrays -eksemplet ovenfor. Når en markør af en type kastes til en anden type af en anden størrelse, bør programmøren forvente, at markørartitmetik vil blive beregnet forskelligt. I C for eksempel, hvis moneyarrayet starter ved 0x2000 og sizeof(int)er 4 bytes, mens det sizeof(char)er 1 byte, money + 1vil det pege på 0x2004, men bags + 1ville pege på 0x2001. Andre risici ved casting omfatter tab af data, når "brede" data skrives til "snævre" placeringer (f.eks. bags[0] = 65537;), Uventede resultater ved bitskiftende værdier og sammenligningsproblemer, især med signerede vs usignerede værdier.

Selvom det generelt er umuligt at afgøre på kompileringstidspunktet, hvilke kast der er sikre, gemmer nogle sprog oplysninger om løbetidstypen, som kan bruges til at bekræfte, at disse farlige kast er gyldige i løbetid. Andre sprog accepterer blot en konservativ tilnærmelse af sikre kast, eller slet ingen.

Værdien af ​​pointer

I C og C ++ er resultatet af sammenligning mellem pointers udefineret. På disse sprog og LLVM fortolkes reglen således, at "bare fordi to pointer peger på den samme adresse, betyder det ikke, at de er ens og kan bruges i flæng", forskellen mellem pointerne omtales som deres herkomst . Selvom casting til en heltalstype som f.eks. uintptr_tTilbyder sammenligning, er selve casten implementeringsdefineret. Yderligere vil yderligere konvertering til bytes og regning kaste optimister fra sig, der forsøger at holde styr på brugen af ​​pointer, et problem, der stadig belyses i akademisk forskning.

Gør tips mere sikre

Da en markør tillader et program at forsøge at få adgang til et objekt, der muligvis ikke er defineret, kan pegepinde være oprindelsen til en række programmeringsfejl . Nytten af ​​pointers er imidlertid så stor, at det kan være svært at udføre programmeringsopgaver uden dem. Derfor har mange sprog skabt konstruktioner designet til at give nogle af de nyttige funktioner i pointer uden nogle af deres faldgruber , også undertiden omtalt som pointer -farer . I denne sammenhæng omtales pointer, der direkte adresserer hukommelse (som brugt i denne artikel)rå pointer s, i modsætning tilsmart tipseller andre varianter.

Et stort problem med pointers er, at så længe de kan manipuleres direkte som et tal, kan de få dem til at pege på ubrugte adresser eller på data, der bruges til andre formål. Mange sprog, herunder de fleste funktionelle programmeringssprog og nyere tvingende sprog som Java , erstatter pointer med en mere uigennemsigtig type referencer, der typisk kun kaldes en reference , som kun kan bruges til at henvise til objekter og ikke manipuleres som tal, hvilket forhindrer dette fejltype. Arrayindeksering håndteres som et specielt tilfælde.

En markør, der ikke er tildelt nogen adresse, kaldes en vild markør . Ethvert forsøg på at bruge sådanne uinitialiserede pointers kan forårsage uventet adfærd, enten fordi den oprindelige værdi ikke er en gyldig adresse, eller fordi brug af den kan beskadige andre dele af programmet. Resultatet er ofte en segmenteringsfejl , overtrædelse af lagring eller vild gren (hvis den bruges som funktionsmarkør eller grenadresse).

I systemer med eksplicit hukommelsestildeling er det muligt at oprette en dinglende markør ved at fordele den hukommelsesregion, den peger ind i. Denne type markør er farlig og subtil, fordi en deallokeret hukommelsesregion kan indeholde de samme data, som den gjorde, før den blev dealloceret, men kan derefter omfordeles og overskrives af ikke -relateret kode, ukendt af den tidligere kode. Sprog med skraldespand forhindrer denne type fejl, fordi deallocation udføres automatisk, når der ikke er flere referencer i omfang.

Nogle sprog, som C ++ , understøtter smarte tips , der bruger en simpel form for referencetælling til at hjælpe med at spore allokering af dynamisk hukommelse ud over at fungere som en reference. I mangel af referencecyklusser, hvor et objekt indirekte refererer til sig selv gennem en sekvens af smarte pointer, eliminerer disse muligheden for dinglende pointer og hukommelseslækager. Delphi -strenge understøtter referencetælling indbygget.

Den programmeringssproget Rust introducerer en låne brik , pointer levetid , og en optimering baseret omkring valgfrie typer for null pointers at fjerne markøren bugs, uden at ty til garbage collection .

Særlige former for tip

Typer defineret efter værdi

Nul markør

En nullmarkør har en værdi forbeholdt til at angive, at markøren ikke refererer til et gyldigt objekt. Nul -pointer bruges rutinemæssigt til at repræsentere forhold såsom afslutningen på en liste over ukendt længde eller manglende handling. denne brug af null -pointers kan sammenlignes med nullable -typer og med ingenting -værdien i en optionstype .

Dinglende markør

En dinglende markør er en markør, der ikke peger på et gyldigt objekt og derfor kan få et program til at gå ned eller opføre sig underligt. I programmeringssprogene Pascal eller C kan pointer, der ikke er initialiseret specifikt, pege på uforudsigelige adresser i hukommelsen.

Følgende eksempelkode viser en dinglende markør:

int func(void) {
    char *p1 = malloc(sizeof(char)); /* (undefined) value of some place on the heap */
    char *p2;       /* dangling (uninitialized) pointer */
    *p1 = 'a';      /* This is OK, assuming malloc() has not returned NULL. */
    *p2 = 'b';      /* This invokes undefined behavior */
}

Her p2kan pege hen overalt i hukommelsen, så udførelse af tildelingen *p2 = 'b';kan ødelægge et ukendt hukommelsesområde eller udløse en segmenteringsfejl .

Vild gren

Hvor en markør bruges som adressen på indgangspunktet til et program eller start på en funktion, der ikke returnerer noget og også er enten ikke -initialiseret eller ødelagt, hvis der alligevel foretages et opkald eller spring til denne adresse, vil en " vild gren "siges at være sket. Med andre ord er en vild gren en funktionsmarkør, der er vild (dinglende).

Konsekvenserne er normalt uforudsigelige, og fejlen kan vise sig på flere forskellige måder afhængigt af, om markøren er en "gyldig" adresse eller ej, og om der (tilfældigt) er en gyldig instruktion (opcode) på denne adresse eller ej. Opdagelsen af ​​en vild gren kan præsentere en af ​​de vanskeligste og frustrerende fejlfindingsøvelser, da mange af beviserne måske allerede er blevet ødelagt på forhånd eller ved udførelse af en eller flere upassende instruktioner på filialplaceringen. Hvis det er tilgængeligt, kan en instruktionssæt -simulator normalt ikke kun detektere en vild gren, før den træder i kraft, men også give et fuldstændigt eller delvis spor af dens historie.

Typer defineret af struktur

Autorelativ markør

En autorelativ markør er en markør, hvis værdi fortolkes som en forskydning fra adressen på selve markøren; Hvis en datastruktur har et autorelativt markørelement, der peger på en del af selve datastrukturen, kan datastrukturen således flyttes i hukommelsen uden at skulle opdatere værdien af ​​den automatiske relative markør.

Det citerede patent bruger også udtrykket selvrelativ pointer til at betyde det samme. Betydningen af ​​dette udtryk er imidlertid blevet brugt på andre måder:

  • at betyde en forskydning fra adressen på en struktur frem for adressen på selve markøren;
  • at betyde en markør, der indeholder sin egen adresse, som kan være nyttig til i enhver vilkårlig region af hukommelsen at rekonstruere en samling af datastrukturer, der peger på hinanden.

Baseret markør

En baseret markør er en markør, hvis værdi er en forskydning fra værdien af ​​en anden markør. Dette kan bruges til at gemme og indlæse blokke af data og tildele adressen til begyndelsen af ​​blokken til basismarkøren.

Typer defineret ved brug eller datatype

Flere indirekte

På nogle sprog kan en markør referere til en anden markør, der kræver flere dereferenceoperationer for at komme til den oprindelige værdi. Selvom hvert indirekte niveau kan tilføje en ydelsesomkostning, er det nogle gange nødvendigt for at give korrekt adfærd for komplekse datastrukturer . For eksempel er det i C typisk at definere en sammenkædet liste i form af et element, der indeholder en markør til det næste element på listen:

struct element {
    struct element *next;
    int            value;
};

struct element *head = NULL;

Denne implementering bruger en markør til det første element på listen som en surrogat for hele listen. Hvis der tilføjes en ny værdi til begyndelsen af ​​listen, headskal den ændres for at pege på det nye element. Da C-argumenter altid sendes efter værdi, tillader indsættelse at blive implementeret korrekt ved hjælp af dobbelt indirektion og har den ønskelige bivirkning at eliminere special case-kode for at håndtere indsættelser forrest på listen:

// Given a sorted list at *head, insert the element item at the first
// location where all earlier elements have lesser or equal value.
void insert(struct element **head, struct element *item) {
    struct element **p;  // p points to a pointer to an element
    for (p = head; *p != NULL; p = &(*p)->next) {
        if (item->value <= (*p)->value)
            break;
    }
    item->next = *p;
    *p = item;
}

// Caller does this:
insert(&head, item);

I dette tilfælde, hvis værdien af itemer mindre end værdien af head, bliver opkalderen headkorrekt opdateret til adressen på det nye element.

Et grundlæggende eksempel er i argv -argumentet til hovedfunktionen i C (og C ++) , som er givet i prototypen som char **argv- det er fordi variablen i argvsig selv er en markør til en række strenge (en matrix af arrays), så *argver en markør til den 0. streng (efter konventionen programmets navn), og **argver den 0. tegn i den 0. streng.

Funktionsmarkør

På nogle sprog kan en markør referere til eksekverbar kode, dvs. den kan pege på en funktion, metode eller procedure. En funktionsmarkør gemmer adressen på en funktion, der skal påberåbes. Selvom denne facilitet kan bruges til at kalde funktioner dynamisk, er det ofte en yndet teknik til virus og andre ondsindede softwareforfattere.

int sum(int n1, int n2) {   // Function with two integer parameters returning an integer value
    return n1 + n2;
}

int main(void) {
    int a, b, x, y;
    int (*fp)(int, int);    // Function pointer which can point to a function like sum
    fp = &sum;              // fp now points to function sum
    x = (*fp)(a, b);        // Calls function sum with arguments a and b
    y = sum(a, b);          // Calls function sum with arguments a and b
}

Tilbage markør

I dobbelt sammenkædede lister eller træstrukturer peger en tilbage -markør på et element 'tilbage' til det element, der refererer til det aktuelle element. Disse er nyttige til navigation og manipulation på bekostning af større hukommelsesbrug.

Simulering ved hjælp af et matrixindeks

Det er muligt at simulere markøradfærd ved hjælp af et indeks til en (normalt endimensionel) matrix.

Primært til sprog, som ikke understøtter pegepinde udtrykkeligt, men gøre support arrays, den vifte kan opfattes og behandles som om det var hele hukommelsen område (inden for rammerne af den særlige array) og enhver indeks for det kan opfattes som ækvivalente til et generelt formål i samlingssprog (der peger på de enkelte bytes, men hvis faktiske værdi er i forhold til arrayets start, ikke dens absolutte adresse i hukommelsen). Antages arrayet er, siger en sammenhængende 16 megabyte karakter datastruktur , individuelle byte (eller en streng af tilstødende bytes i array) kan adresseres direkte og manipuleres ved hjælp af navnet af arrayet med en 31 bit unsigned heltal som simulerede pointer (dette ligner ganske vist C -arrays -eksemplet vist ovenfor). Markør -aritmetik kan simuleres ved at tilføje eller trække fra indekset, med minimal ekstra omkostninger sammenlignet med ægte markør -aritmetik.

Det er endda teoretisk muligt ved hjælp af ovenstående teknik sammen med en passende instruktionssæt -simulator at simulere enhver maskinkode eller mellemproduktet ( byte -kode ) for enhver processor /sprog på et andet sprog, der slet ikke understøtter pointers (f.eks. Java / JavaScript ). For at opnå dette kan den binære kode i første omgang indlæses i sammenhængende bytes i arrayet, så simulatoren kan "læse", fortolke og handle helt inden for hukommelsen i det samme array. Om nødvendigt helt at undgå buffer overflow problemer, begrænsningskontrol kan normalt actioned for compileren (eller hvis ikke, håndkodede i simulatoren).

Support i forskellige programmeringssprog

Ada

Ada er et stærkt indtastet sprog, hvor alle tips er indtastet, og kun sikre typekonverteringer er tilladt. Alle pointer er som standard initialiseret til null, og ethvert forsøg på at få adgang til data via en nullmarkør bevirker, at en undtagelse rejses. Pegere i Ada kaldes adgangstyper . Ada 83 tillod ikke aritmetik om adgangstyper (selvom mange compiler-leverandører leverede det som en ikke-standardfunktion), men Ada 95 understøtter "sikker" regning om adgangstyper via pakken System.Storage_Elements.

GRUNDLÆGGENDE

Flere gamle versioner af BASIC til Windows -platformen understøttede STRPTR () for at returnere adressen til en streng, og for VARPTR () at returnere adressen til en variabel. Visual Basic 5 havde også understøttelse af OBJPTR () til at returnere adressen til en objektgrænseflade og til en ADDRESSOF -operatør til at returnere adressen til en funktion. Typerne af alle disse er heltal, men deres værdier svarer til dem, der holdes af markørtyper.

Nyere dialekter af BASIC , såsom FreeBASIC eller BlitzMax , har imidlertid udtømmende pointerimplementeringer. I FreeBASIC behandles aritmetik på ANYpointer (svarende til C'er void*), som om ANYmarkøren var en bytebredde. ANYpointers kan ikke aflæses, som i C. Desuden ANYgenererer casting mellem og andre typers tips ikke nogen advarsler.

dim as integer f = 257
dim as any ptr g = @f
dim as integer ptr i = g
assert(*i = 257)
assert( (g + 4) = (@f + 1) )

C og C ++

I C og C ++ er pointer variabler, der gemmer adresser og kan være nul . Hver markør har en type, den peger på, men man kan frit kaste mellem markørtyper (men ikke mellem en funktionsmarkør og en objektmarkør). En særlig markørtype kaldet "void pointer" gør det muligt at pege på et hvilket som helst (ikke-funktionelt) objekt, men er begrænset af, at det ikke kan afgøres direkte (det skal støbes). Selve adressen kan ofte manipuleres direkte ved at caste en markør til og fra en integreret type af tilstrækkelig størrelse, selvom resultaterne er implementeringsdefinerede og faktisk kan forårsage udefineret adfærd; mens tidligere C -standarder ikke havde en integreret type, der garanteret var stor nok, specificerer C99 det uintptr_t typedef -navn, der er defineret i <stdint.h>, men en implementering behøver ikke at give det.

C ++ understøtter fuldt ud C -pointer og C typecasting. Det understøtter også en ny gruppe af typecasting-operatører, der hjælper med at fange nogle utilsigtede farlige kast ved kompileringstidspunktet. Siden C ++ 11 giver C ++ - standardbiblioteket også smarte tips ( unique_ptr, shared_ptrog weak_ptr), der kan bruges i nogle situationer som et sikrere alternativ til primitive C -pointer. C ++ understøtter også en anden form for reference, ganske anderledes end en markør, kaldet blot en reference eller referencetype .

Markør aritmetik , det vil sige evnen til at ændre en markørs måladresse med aritmetiske operationer (samt størrelses sammenligninger), er begrænset af sprogstandarden til at forblive inden for grænserne for et enkelt array -objekt (eller lige efter det), og vil ellers påberåbe sig udefineret adfærd . Tilføjelse eller subtraktion fra en markør flytter den med et multiplum af størrelsen på dens datatype . For eksempel vil tilføjelse af 1 til en markør til 4-bytes heltalsværdier øge markørens spids-til-byte-adresse med 4. Dette har den virkning, at markøren øges til at pege på det næste element i en sammenhængende række af heltal-hvilket er ofte det tilsigtede resultat. Markørregning kan ikke udføres på voidpointer, fordi hulrumstypen ikke har nogen størrelse, og dermed kan den spidse adresse ikke føjes til, selvom gcc og andre kompilatorer vil udføre byte-aritmetik på void*som en ikke-standardudvidelse og behandle den som om den var char *.

Markørregning giver programmereren en enkelt måde at håndtere forskellige typer: tilføjelse og fradrag af antallet af nødvendige elementer i stedet for den faktiske forskydning i bytes. (Markør aritmetik med char *pointers bruger byte -forskydninger, fordi det sizeof(char)er 1 pr. Definition.) Specielt erklærer C -definitionen eksplicit, at syntaksen a[n], som er det n-element i arrayet a, svarer til *(a + n), hvilket er indholdet af elementet af a + n. Dette indebærer, at n[a]det svarer til a[n], og man kan skrive, fx a[3]eller 3[a]lige godt for at få adgang til det fjerde element i en matrix a.

Selv om den er kraftfuld, kan pegearitmetik være en kilde til computerfejl . Det har tendens til at forvirre nybegyndere programmører , tvinger dem ind i forskellige sammenhænge: et udtryk kan være en almindelig aritmetiske én eller en pegepind aritmetisk én, og nogle gange er det nemt at fejltagelse ene for den anden. Som svar på dette tillader mange moderne computerprogrammer på højt niveau (f.eks. Java ) ikke direkte adgang til hukommelse ved hjælp af adresser. Den sikre C -dialekt Cyclone løser også mange af problemerne med pointers. Se C programmeringssprog for mere diskussion.

Den voidpointer , eller void*, understøttes i ANSI C og C ++ som et generisk henvisningstype. En markør til voidkan gemme adressen på ethvert objekt (ikke funktion), og i C konverteres implicit til en hvilken som helst anden objektpegertype ved tildeling, men den skal eksplicit kastes, hvis du afskriver. K&R C bruges char*til formålet "type-agnostisk markør" (før ANSI C).

int x = 4;
void* p1 = &x;
int* p2 = p1;       // void* implicitly converted to int*: valid C, but not C++
int a = *p2;
int b = *(int*)p1;  // when dereferencing inline, there is no implicit conversion

C ++ tillader ikke den implicitte konvertering af void*til andre pegertyper, selv i tildelinger. Dette var en designbeslutning for at undgå skødesløse og endda utilsigtede kast, selvom de fleste kompilatorer kun udsender advarsler, ikke fejl, når de støder på andre kast.

int x = 4;
void* p1 = &x;
int* p2 = p1;                     // this fails in C++: there is no implicit conversion from void*
int* p3 = (int*)p1;               // C-style cast
int* p4 = static_cast<int*>(p1);  // C++ cast

I C ++ er der ingen void&(henvisning til tomrum) for at komplementere void*(markør til tomrum), fordi referencer opfører sig som aliasser til de variabler, de peger på, og der kan aldrig være en variabel, hvis type er void.

Oversigt over markørerklæringens syntaks

Disse markørerklæringer dækker de fleste varianter af markørerklæringer. Selvfølgelig er det muligt at have triple pointers, men hovedprincipperne bag en triple pointer findes allerede i en double pointer.

char cff [5][5];    /* array of arrays of chars */
char *cfp [5];      /* array of pointers to chars */
char **cpp;         /* pointer to pointer to char ("double pointer") */
char (*cpf) [5];    /* pointer to array(s) of chars */
char *cpF();        /* function which returns a pointer to char(s) */
char (*CFp)();      /* pointer to a function which returns a char */
char (*cfpF())[5];  /* function which returns pointer to an array of chars */
char (*cpFf[5])();  /* an array of pointers to functions which return a char */

() Og [] har en højere prioritet end *.

C#

I programmeringssproget C# understøttes kun pointer under visse betingelser: enhver kodeblok inklusive pointer skal markeres med unsafesøgeordet. Sådanne blokke kræver normalt højere sikkerhedstilladelser for at få lov til at køre. Syntaksen er i det væsentlige den samme som i C ++, og den pegede adresse kan enten være administreret eller ikke -administreret hukommelse. Henvisninger til administreret hukommelse (enhver markør til et administreret objekt) skal imidlertid deklareres ved hjælp af fixednøgleordet, som forhindrer skraldesamleren i at flytte det spidse objekt som en del af hukommelsesstyring, mens markøren er i omfang, og dermed holde markøradressen gyldig.

En undtagelse hertil er fra at bruge IntPtrstrukturen, som er et sikkert administreret svarende til int*, og ikke kræver usikker kode. Denne type returneres ofte, når der bruges metoder fra System.Runtime.InteropServicesf.eks.

// Get 16 bytes of memory from the process's unmanaged memory
IntPtr pointer = System.Runtime.InteropServices.Marshal.AllocHGlobal(16);

// Do something with the allocated memory

// Free the allocated memory
System.Runtime.InteropServices.Marshal.FreeHGlobal(pointer);

Den NET Framework indeholder mange klasser og metoder i Systemog System.Runtime.InteropServicesnamespaces (såsom Marshalklasse), som omformer .NET typer (for eksempel System.String) til og fra mange unmanaged typer og pejlemærker (f.eks LPWSTReller void*) for at tillade kommunikation med ikke-administreret kode . De fleste sådanne metoder har de samme krav til sikkerhedstilladelse som ikke -administreret kode, da de kan påvirke vilkårlige steder i hukommelsen.

COBOL

De COBOL programmeringssprog understøtter pegepinde til variabler. Primitive eller gruppe (registrer) dataobjekter, der er deklareret inden LINKAGE SECTIONfor et program, er iboende markørbaserede, hvor den eneste hukommelse, der er allokeret i programmet, er plads til adressen på dataposten (typisk et enkelt hukommelsesord). I programkildekode bruges disse dataelementer ligesom enhver anden WORKING-STORAGEvariabel, men indholdet er implicit tilgået indirekte via deres LINKAGEtip.

Hukommelsesplads for hvert peget dataobjekt tildeles typisk dynamisk ved hjælp af eksterne CALLudsagn eller via indlejrede udvidede sprogkonstruktioner såsom EXEC CICSeller EXEC SQLsætninger.

Udvidede versioner af COBOL giver også markørvariabler, der er deklareret med USAGE IS POINTERklausuler. Værdierne for sådanne markørvariabler etableres og ændres ved hjælp af SETog SET ADDRESSudsagn.

Nogle udvidede versioner af COBOL indeholder også PROCEDURE-POINTERvariabler, som er i stand til at lagre adresserne på den eksekverbare kode .

PL/I

Den PL / I sproget giver fuld støtte til henvisninger til alle datatyper (herunder henvisninger til strukturer), rekursion , multitasking , string håndtering, og omfattende indbyggede funktioner . PL/I var et stort spring fremad i forhold til sin tids programmeringssprog. PL/I -pointers er ikke -typede, og derfor er ingen casting påkrævet til pointer dereferencing eller tildeling. Deklarationssyntaksen for en markør er DECLARE xxx POINTER;, som erklærer en markør med navnet "xxx". Pegere bruges med BASEDvariabler. En baseret variabel kan erklæres med en standardlokalisator ( DECLARE xxx BASED(ppp);eller uden ( DECLARE xxx BASED;), hvor xxx er en baseret variabel, som kan være en elementvariabel, en struktur eller en matrix, og ppp er standardmarkøren). En sådan variabel kan være adresse uden en eksplicit markørreference ( xxx=1;, eller kan adresseres med en eksplicit henvisning til standardlokalisatoren (ppp) eller til enhver anden markør ( qqq->xxx=1;).

Markørregning er ikke en del af PL/I -standarden, men mange kompilatorer tillader udtryk for formularen ptr = ptr±expression. IBM PL/I har også den indbyggede funktion PTRADDtil at udføre regning. Markør aritmetik udføres altid i bytes.

IBM Enterprise PL/I -kompilatorer har en ny form for maskinskrevet markør kaldet a HANDLE.

D

Det sprog D programmering er et derivat af C og C ++, som fuldt ud støtter C pointers og C typecasting.

Eiffel

Det Eiffel objektorienterede sprog anvender værdi- og referencesemantik uden pegearitmetik. Ikke desto mindre tilbydes markørklasser. De tilbyder markørregning, typecasting, eksplicit hukommelsesstyring, grænseflade med ikke-Eiffel-software og andre funktioner.

Fortran

Fortran-90 introducerede en stærkt indtastet markørkapacitet. Fortran -pointers indeholder mere end bare en simpel hukommelsesadresse. De indkapsler også de nedre og øvre grænser for matrixdimensioner, skridt (f.eks. For at understøtte vilkårlige array -sektioner) og andre metadata. En forening operatør , =>der bruges til at knytte en POINTERtil en variabel, der har en TARGETattribut. Fortran-90- ALLOCATEsætningen kan også bruges til at knytte en markør til en hukommelsesblok. For eksempel kan følgende kode bruges til at definere og oprette en sammenkædet listestruktur:

type real_list_t
  real :: sample_data(100)
  type (real_list_t), pointer :: next => null ()
end type

type (real_list_t), target :: my_real_list
type (real_list_t), pointer :: real_list_temp

real_list_temp => my_real_list
do
  read (1,iostat=ioerr) real_list_temp%sample_data
  if (ioerr /= 0) exit
  allocate (real_list_temp%next)
  real_list_temp => real_list_temp%next
end do

Fortran-2003 tilføjer support til procedurepunkter. Som en del af C-interoperabilitetsfunktionen understøtter Fortran-2003 også iboende funktioner til konvertering af pointer i C-stil til Fortran-pointers og tilbage.

Go har tips. Dets erklæringssyntaks svarer til C, men skrevet omvendt og slutter med typen. I modsætning til C har Go skraldesamling og tillader ikke markørregning. Referencetyper, som i C ++, findes ikke. Nogle indbyggede typer, f.eks. Kort og kanaler, er i boks (dvs. internt er de pointer til mutable strukturer) og initialiseres ved hjælp af makefunktionen. I en tilgang til ensartet syntaks mellem pointers og non-pointers er pilen ( ->) blevet droppet: dot-operatoren på en markør refererer til feltet eller metoden for det dereferenserede objekt. Dette fungerer imidlertid kun med 1 indirekte niveau.

Java

Der er ingen eksplicit fremstilling af pointer i Java . I stedet implementeres mere komplekse datastrukturer som objekter og arrays ved hjælp af referencer . Sproget giver ikke eksplicitte operatører til markørmanipulation. Det er dog stadig muligt for kode at forsøge at afskrive en nullreference (nullmarkør), hvilket resulterer i, at en undtagelse i løbetid kastes. Den plads, der optages af hukommelsesobjekter uden reference, genoprettes automatisk ved affaldssamling ved løbetid.

Modula-2

Pegere implementeres i høj grad som i Pascal, ligesom VARparametre i procedurekald. Modula-2 er endnu stærkere skrevet end Pascal, med færre måder at undslippe typesystemet. Nogle af varianterne af Modula-2 (såsom Modula-3 ) inkluderer affaldssamling.

Oberon

Ligesom med Modula-2 er der tips til rådighed. Der er stadig færre måder at unddrage sig typesystemet, og derfor er Oberon og dens varianter stadig sikrere med hensyn til pointer end Modula-2 eller dens varianter. Som med Modula-3 er affaldssamling en del af sprogspecifikationen.

Pascal

I modsætning til mange sprog, der indeholder pointer, tillader standard ISO Pascal kun pointer at referere til dynamisk oprettede variabler, der er anonyme og ikke tillader dem at referere til statiske eller lokale variabler. Det har ikke pegearitmetik. Pegere skal også have en tilhørende type, og en markør til en type er ikke kompatibel med en markør til en anden type (f.eks. Er en markør til et tegn ikke kompatibel med en markør til et helt tal). Dette hjælper med at fjerne de typen sikkerhedsproblemer forbundet med andre pointer implementeringer, især dem, der anvendes til PL / I eller C . Det fjerner også nogle risici forårsaget af dinglende pointer , men muligheden for dynamisk at give slip på det refererede rum ved hjælp af disposestandardproceduren (som har samme effekt som freebiblioteksfunktionen i C ) betyder, at risikoen for dinglende pointer ikke har været helt elimineret.

I nogle kommercielle og open source Pascal (eller derivater) kompilatorimplementeringer - som Free Pascal , Turbo Pascal eller Object Pascal i Embarcadero Delphi - får en markør imidlertid lov til at henvise til statiske eller lokale variabler, der er standard, og kan kastes fra en pegertype til en anden. Desuden er markørregning ubegrænset: tilføjelse eller fradrag af en markør flytter den med det antal bytes i begge retninger, men ved hjælp af Inceller Decstandardprocedurer med den flyttes markøren efter størrelsen på den datatype, den erklæres at pege på. En ikke -indtastet markør findes også under navnet Pointer, som er kompatibel med andre markørtyper.

Perl

Den Perl programmeringssprog understøtter pointere, selvom sjældent brugt, i form af den pakke ud funktioner. Disse er kun beregnet til simple interaktioner med kompilerede OS -biblioteker. I alle andre tilfælde bruger Perl referencer , som er indtastet og ikke tillader nogen form for pegearitmetik. De bruges til at konstruere komplekse datastrukturer.

Se også

Referencer

eksterne links