ANSI C

A folyamatok kezeléséhez szükséges ANSI C utasítások összefoglalója...


 

  C. Hogyan?

  gcc

  Környezet, szövegszerkesztő

  vi

  Segítség

  man

  A parancssor paraméterei és a környezeti változók

  argc   argv   envp

  env

  environ

  getenv

  Hibakezelés

  errno

  strerror

  perror

  err.c  –  err_sys   err_ret   err_quit   err_msg   err_dump

  Memóriakezelés

  malloc

  calloc

  realloc

  free

  Aktuális könyvtár váltása (chdir)

  Gyökérkönyvtár megváltoztatása (chroot)

 


 

  Folyamatok közti kommunikáció

  C. Hogyan?

A Unix alatt használható ANSI C nagyrészt megegyezik a Borland C-vel.

Különbségek, megjegyzések:

- nincs conio.h
- nincs nyomkövetés (a tesztelésre a legjobb módszer, ha több
printf-et szúrunk be a programunkba)
- az ANSI C fájlok kiterjesztése kötelezően
.c
- a C++ fájlok kiterjesztése kötelezően
.C
- a printf csak a sorvége jel (\n) után ír a képernyőre

A fordítás a gcc nevű fordítóval történik.

$ gcc program.c

A parancs paraméter nélkül használva mindig létrehoz egy a.out nevű állományt. Ez lesz a kimenet: bináris, futtatható kód. Ha mi szeretnénk nevet adni a kimenetnek, akkor használjuk a -o opciót.

$ gcc program.c -o futtathato

Mind a két esetben a kimeneti fájl már rendelkezik a futtatható (x) attribútummal.

Az így kapott programot futtathatjuk, ha egyszerűen beírjuk a nevét (egyes Unix verziókban meg kell adnunk az útvonalat még akkor is, ha a fájl az aktuális könyvtárban található):

$ ./futtathato

Ha több állományból álló programot (projektet) írunk, ezeket a make paranccsal kapcsoljuk össze.

  Környezet, szövegszerkesztő

Amint láttuk gcc-nek nincs saját kezelőfelülete, szövegszerkesztője. Ezért a programunkat bármilyen szerkesztőben begépelhetjük. A különböző Unix verziók rengeteg ilyen (szebbnél szebb) alkalmazást tartalmaznak.

Egy biztos: a vi szövegszerkesztő mindenik verzióban megtalálható.

Használati útmutató:

- ne ijedjünk meg, nem olyan vészes, mint amilyennek elsőre látszik
- elindítása: vi vagy vi program.c
- gépelés elkezdése: INSERT billentyűvel (ezzel egyébként válthatunk beszúrási/felülírási mód között)
- parancs üzemmódba váltás (minden parancs kiadása előtt kötelező): ESC
- kilépés: :q
- állomány mentése (ha van már neve): :w
- állomány mentése (ha még nincs neve): :w név
- mentés, kilépés: :wq
- kilépés mentés nélkül: :q!

Jól használható szövegszerkesztő még a joe, emacs stb.

  Segítség

Akárcsak a shell parancsok esetén a man program C utasításokról is nagyon sok információt tartalmaz.

Például:

$ man printf

  A parancssor paraméterei és a környezeti változók

Amikor egy folyamat elindít egy programot, átadja neki a parancssor paramétereit és a környezeti változókat. Ahhoz, hogy programunk ezeket a változókat használni tudja a főprogramot a következőképpen kell deklarálnunk:

main(int argc, char *argv[], char *envp[])

A parancssor paramétereit az argv, a környezeti változókat pedig az envp által mutatott táblázat (vektor) tartalmazza. Az argv elemeinek számát az argc változó tartalmazza.

A paraméterek és a környezeti változók kiírása történhet például így:

for (k=0; k<argc; ++k)
{
  printf("a %d. parameter: %s\n", k+1, argv[k]);
}

for (k=0; ; ++k)
{
  if (envp[k][0])
  {
    printf("a %d. kornyezeti valtozo: %s\n", k+1, envp[k]);
  }
  else break;
}

A környezeti változók néhány karaktersorból állnak. Formájuk:

NÉV = érték

A leggyakoribb ilyen változók:

HOME – azt a könyvtárat jelöli, amelybe egy cd utasítás hatására ugrik
PATH – azon könyvtárak listája ahol a shell a kiadott parancsokat keresi
MAIL – a leveleket tartalmazó fájl neve
TERM – a terminál típusa
SHELL – a bináris shell állomány elérési útvonala
LOGNAME – a név amelyen a felhasználót a rendszer nyilvántartja
PS1 – a shell prompt jele (alapért. $)
PS2 – a prompt további sorainak jele (alapért. >)

A Unix shellből az env parancsot kiadva megjeleníthetők a környezeti változók értékei.

A környezeti változók értékének programból történő meghatározásában nem az envp az egyetlen lehetőség. Használhatjuk az environ külső változót is, amely éppen a rendszer által tárolt táblázatra mutat.

extern char **environ;

main()
{
  int k;
  for (k=0; ; ++k)
    if (environ[k][0])
    {
      printf("a %d. kornyezeti valtozo: %s\n", k+1, environ[k]);
    }
    else break;
}

Az envp és az environ változók ugyanazt az eredményt adják.

Egy bizonyos környezeti változó értékét lekérdezhetjük a getenv változóval:

#include <stdlib.h>
char *getenv(const char *nev);

A függvény egy pointert ad vissza, amely a nev környezeti változóhoz hozzárendelt értékre mutat. Értéke NULL, ha nem létezik ilyen nevű változó.

char *terminal;
if ((terminal = getenv("TERM")) == NULL)
{
  printf("a TERM kornyezeti valtozo nincs definialva\n");
  exit(1);
}
printf("a terminal: %s\n", terminal); 

A fenti példa lekérdezi a terminál értékét, amennyiben a változónak nincs értéke hibaüzenetet ad.

  Hibakezelés

Unixban egy függvényhívás következtében fellépő hiba esetén a legtöbb függvény -1 értéket térít vissza. Ilyen esetekben a hiba kódját az errno globális változó tartalmazza. Ez azonban nem egy elfogadott szabály, hiszen egyes függvények NULL értéket adnak vissza.

Az errno.h deklarációs fájlban van definiálva az errno változó, valamint azon szimbolikus konstansok értékei, amelyeket ez a változó felvehet. Az errno nem veheti fel a 0 értéket, és a szimbolikus konstansok között sincs 0 értékű.

extern int errno;

Amennyiben egy függvény nem hibával zárul, az előző errno érték megmarad!

A standard C két függvényt definiál a hibaüzenetek kiírására (szöveggel történő meghatározására). Az egyik az strerror, amelynek alakja:

#include <string.h>
char *strerror(int nrerr);

A függvény egy pointert térít vissza a hiba szövegéhez. Az nrerr rendszerint az errno változó szokott lenni, de megadhatunk tetszőleges hibakódot is.

A másik hibaértelmező függvény a perror; ennek szintaxisa:

#include <stdio.h>
void perror(const char *msg);

A függvény a standard hibacsatornára kiírja az msg szöveget, egy : (kettőspontot), majd az errno változó által meghatározott hibaüzenetet.

Az egyes hibakódokhoz tartozó hibaüzenetek listája megtalálható a Függelékben.

Az alábbiakban definiálunk néhány olyan függvényt, amelyek leegyszerűsítik a hibakezelést. A továbbiakban a példaprogramokban is ezeket a függvényeket fogjuk felhasználni. A függvények működését a következő táblázat foglalja össze:

Függvények

strerror(errno)

Befejeződés

err_sys

igen

exit(1);

err_ret

igen

return;

err_quit

nem

exit(1);

err_msg

nem

return;

err_dump

igen

abort();

A függvények definíciója az err.c állományban található.

(A fenti függvények alapötlete és a mellékelt kód Iosif Ignat, Adrian Kacso UNIX – Gestionarea proceselor című könyvéből származik)

  Memóriakezelés

  malloc

Lefoglal egy megadott méretű (meret) memóriaterületet. A lefoglalt memóriazónát nem inicializálja semmilyen értékkel. Alakja:

#include <stdlib.h>
void *malloc(size_t meret);

A függvény 0-tól különböző értéket ad, ha a lefoglalás sikeres volt, és NULL-t, ha sikertelen (ekkor a hiba kódját az errno tartalmazza). Az első esetben a visszatérített érték éppen a lefoglalt memóriaterület kezdetére mutató pointer lesz.

Példa:

void *ptr;
if ((ptr = malloc(10000)) == NULL)
{
  perror("malloc");
  exit(1);
}

  calloc

Lefoglal egy elemszam*meret nagyságú folytonos memóriaterületet – magyarul elemszam darab, egyenként meret nagyságú területet –, majd ezt NULL értékekkel tölti fel. Alakja:

#include <stdlib.h>
void *calloc(size_t elemszam, size_t meret);

Sikeres lefoglalás esetén 0-tól különböző értéket térít vissza (pointer a lefoglalt memóriazónára), különben a NULL értéket.

Példa:

struct
{
  int s1;
  long s2;
  char s3[10];
} s;

void *ptr;

if ((ptr = calloc(10, sizeof(s))) == NULL)
{
  perror("calloc");
  exit(1);
}

  realloc

Átméretez egy malloc, calloc vagy realloc függvénnyel lefoglalt memóriaterületet uj_meret nagyságúra. Alakja:

#include <stdlib.h>
void *realloc(void *ptr, size_t uj_meret);

Sikeres lefoglalás esetén egy nem nulla értéket ad vissza (amely lehet a régi mutató, de lehet egy új érték is), különben a NULL-t.

Példa:

void *ptr;

if ((ptr = malloc(10000)) == NULL)
{
  perror("malloc");
  exit(1);
}

if ((ptr = realloc(ptr, 20000)) == NULL)
{
  perror("realloc");
  exit(2);
}

  free

Felszabadít egy a malloc, a calloc vagy a realloc függvénnyel lefoglalt memóriaterületet. Alakja:

#include <stdlib.h>
void free(void *ptr);

Amennyiben a megadott pointer nem létezik a függvény furcsán viselkedhet!

Példa:

void *ptr;

if ((ptr = malloc(10000)) == NULL)
{
  perror("malloc");
  exit(1);
}

free(ptr);

  Aktuális könyvtár váltása (chdir)

Minden folyamathoz tartozik egy ún. aktuális könyvtár. Ez a könyvtár határozza meg az összes relatív keresési útvonalat, amelyet a folyamat használ. A folyamathoz tartozó aktuális könyvtárat megváltoztathatjuk a chdir függvény segítségével. Alakja:

#include <unistd.h>
int chdir(const char *path);

A függvény 0-t ad vissza, ha a váltás sikerült, és -1-et hiba esetén. A path változóban az új útvonalat kell megadni (ehhez legalább végrehajtási (x) jogunk kell legyen).

A rendszerbe való belépéskor minden felhasználó a saját gazdakönyvtárából indul. A gazdakönyvtár a felhasználót jellemzi, míg az aktuális könyvtár egy folyamat jellemzője. Vigyázat, a kettőt ne tévesszük össze!

Példa:

#include "hdr.h"

int main(void)
{
  if (chdir("/tmp")<0)
    err_sys("chdir hiba");
  printf("a konyvtarvaltas sikerult\n");
  exit(0);
}

  Gyökérkönyvtár megváltoztatása (chroot)

A gyökérkőnyvtár megváltoztatására való a chroot függvény, melynek alakja:

#include <unistd.h>
int chroot(const char *path);

A függvény 0-t ad vissza, ha a váltás sikerült, és -1-et hiba esetén. A path változóban az új útvonalat kell megadni.

Ezt a függvény azonban csak a superuser hajthatja végre!

  Folyamatokkal végzett műveletek

 


Copyright (C) Buzogány László, 2002

About