Siirry sisältöön

C/Standardikirjastot/stdarg.h

Wikikirjastosta
#include <stdarg.h>

Kun C-funktio esitellään tai määritellään niin, että parametrilista päättyy erikoismerkkiin ..., kyseessä on muuttuvapituinen parametrilista. Tällaiseen listaan voi lisätä edellisen argumentin jälkeen minkä tahansa määrän minkälaisia argumentteja tahansa:

double monen_luvun_summa(const char *tyypit, ...) {
  /* ... */
}
  /* ... */
  monen_luvun_summa("iif", 3, 5, 9.5f);
  monen_luvun_summa("ff", 2.4f, 0.3f);
  monen_luvun_summa("");

Tällaisten funktioiden toteuttamiseen tarvitaan stdarg.h-kirjasto. Se määrittelee tietotyypin va_list, jolla voi käydä läpi kyseistä listaa.

Listasta itsestään ei selviä, montako tai minkätyyppisiä argumenttia annettiin. Ohjelmoijan vastuulle jää selvittää tämä itse, ja sitä varten listan edellä pitää olla edes yksi parametri. Se voi esimerkiksi olla lukumäärä, jos funktio olettaa kaikkien argumenttien tyypin olevan sama, tai merkkijono, josta voidaan päätellä annetut tyypit. Funktio ei toimi kunnolla, jos tyypit päätellään väärin.

void va_start(va_list lista, NIMI);

alustaa va_list-listan niin, että se osoittaa ensimmäiseen argumenttiin parametrin NIMI jälkeen.

T va_arg(va_list lista, T);

poimii listasta seuraavan argumentin, joka on tyyppiä T. Jos seuraava argumentti onkin eri tyyppiä, saatu arvo on kelvoton, ja listasta ei voi hakea enempää parametreja. Huomaathan kuitenkin poikkeukset:

  • osoittimet arvoon (muttei funktioihin) ovat tässä kaikki samaa tyyppiä, tosin saatu osoitin voi olla kelvoton kyseiselle kohdetyypille
  • samankokoiset etumerkilliset ja etumerkittömät kokonaislukutyypit voivat mennä ristiin, kunhan arvon voi esittää molemmilla tyypeillä
  • C:n tavalliset tyyppikorotukset pätevät: int:iä pienemmät etumerkilliset kokonaislukutyypit muuttuvat automaattisesti int:ksi ja unsigned int:iä pienemmät etumerkittömät kokonaislukutyypit muuttuvat automaattisesti unsigned int:ksi. Näiden lisäksi float:eista tulee automaattisesti double:ja.

Kun luetteloa ei enää käytetä, se pitää siivota pois tällä makrolla:

void va_end(va_list lista);

Jos listan haluaa alustaa uudelleen va_start (tai alla käsitellyllä va_copy-makrolla), se pitää ensin siivota va_end:llä. Lista pitää myös siivota ennen funktiosta palaamista.

C99-standardi lisää uuden makron:

void va_copy(va_list kopio, va_list lista);

jota voidaan käyttää va_start:n sijasta. Tällä voidaan 'tallettaa' kohta parametrilistassa kopioon.

Esimerkki: monen_luvun_summa voisi näyttää seuraavalta:

double monen_luvun_summa(const char *tyypit, ...) {
  double summa = 0.0;
  va_list lista;
  va_start(lista, tyypit);
  while (*tyypit) {
    switch (*tyypit++) {
      case 'i':
        summa += va_arg(lista, int); 
        break;
      case 'f':
        summa += va_arg(lista, double);
        break;
    }
  }
  va_end(lista);
  return summa;
}

stdarg.h on yksi harvoista otsikkotiedostoista, joka on saatavilla myös ns. irrallisessa (engl. freestanding) ympäristössä. Tämä tarkoittaa sitä, että otsikkotiedoston määritelmät ovat kääntäjän tiedossa heti jo ohjelmaa kääntäessä, eikä se sisällä funktioita tai muuttujia. Irrallisia ympäristöjä ovat sellaiset, joissa ei ole saatavilla suoritettavaa C-standardikirjaston toteutusta.