Siirry sisältöön

C/Standardikirjastot/setjmp.h

Wikikirjastosta
#include <setjmp.h>

Tämä kirjasto määrittelee rakenteen, jolla voi hypätä takaisin aiemmin suoritettuun paikkaan koodia, vaikka toisen tai useamman funktion sisältä, kunhan kohta pidetään tallella.

jmp_buf

on tietotyyppi. Sisäisesti se on taulukko, joka sisältää kaikki tarvittavat tiedot suoritettavasta kohdasta koodia.

Tämän käyttöön määritellään kaksi makroa:

int setjmp(jmp_buf kohta);

alustaa jmp_buf-tietotyypin niin, että setjmp-funktio voi palata useamman kerran. Ensimmäisellä kerralla se palauttaa nollan ja myöhemmillä kerroilla jonkin muun luvun.

setjmp:n käyttöä on rajoitettu. Sitä saa käyttää vain if-ehtolauseen ehdossa tai switch-lauseen valintamuuttujana, ja silloinkin sen kanssa saa käyttää vain vertailuoperaattoreita tai loogista !-operaattoria, ei muita operaattoreita. Tämän lisäksi sitä saa käyttää myös omassa lausekkeessaan, jonka arvoa ei talleteta mihinkään. Sen arvoa ei saa kuitenkaan esim. tallentaa muuttujaan, tai käyttää ehtolauseessa muiden ehtojen kanssa. (Näin standardi ainakin määrää.)

void longjmp(jmp_buf kohta, int arvo);

hyppää takaisin setjmp:llä alustettuun kohtaan ja palauttaa setjmp:stä kyseisen arvon (paitsi luvun 1, jos annettu arvo on 0). Funktio ei palaa kutsuvaan koodiin.

setjmp:n tarkoitus on toteuttaa esim. poikkeusrakenteet, jossa koodi voi nopeasti hypätä käsittelemään poikkeuksellinen tilanne. Vaihtoehto tälle olisi, että kaikki funktiot palauttavat virhekoodin, joka sitten tarkistetaan. Virhekoodiratkaisu on yleensä selkeämpi, mutta voi olla hitaampi etenkin sellaisessa koodissa, jota suoritetaan erittäin usein.

Esimerkki:

static jmp_buf env;
void sisempi_funktio3(void) {
    puts("sisempi_funktio3 alkaa");
    longjmp(env, 42);  /* nyt hypätään */
    puts("sisempi_funktio3 päättyy");
}
void sisempi_funktio2(void) {
    puts("sisempi_funktio2 alkaa");
    sisempi_funktio3();
    puts("sisempi_funktio2 päättyy");
}
void sisempi_funktio1(void) {
    puts("sisempi_funktio1 alkaa");
    sisempi_funktio2();
    puts("sisempi_funktio1 päättyy");
}
int tee_jotain(void) {
    if (setjmp(env)) {
        puts("ympäri käydään, yhteen tullaan");
    } else {
        sisempi_funktio1();
    }
}

niin tee_jotain() johtaa tulosteeseen:

 sisempi_funktio1 alkaa
 sisempi_funktio2 alkaa
 sisempi_funktio3 alkaa
 ympäri käydään, yhteen tullaan