Szabványos C-könyvtár

C szabványos könyvtár From Wikipedia, the free encyclopedia

Remove ads

A Szabványos C-könyvtár (C standard library), néha libc,[1] a C programozási nyelv szabványos könyvtára, ahogyan azt az ISO C szabvány meghatározza.[2] Az eredeti ANSI C(wd) szabványból kiindulva, a C POSIX könyvtárral(wd) egy időben fejlesztették ki, amely annak szuperhalmaza.[3] Mivel az ANSI C-t a Nemzetközi Szabványügyi Szervezet elfogadta,[4] a C standard könyvtárat ISO C library-nak is nevezik.[5]

A C szabványos könyvtár makrókat, típusdefiníciókat és függvényeket biztosít olyan feladatokhoz, mint a karakterlánc-kezelés, a matematikai számítások, a be- és kimeneti feldolgozás, a memóriakezelés és input/output.

Remove ads

Alkalmazásprogramozási interfész (API)

Fejléc fájlok

A C szabványos könyvtár alkalmazásprogramozási interfésze (API) számos fejlécfájlban(wd) (header files) van deklarálva. Minden fejlécfájl egy vagy több függvénydeklarációt, adattípus-definíciót és makrókat tartalmaz.

Hosszú stabil időszak után három új fejlécfájl (iso646.h, wchar.h és wctype.h) került be az 1995-ben ratifikált C-szabvány Normative Addendum 1 (NA1) kiegészítésével. További hat fejlécfájl (complex.h, fenv.h, inttypes.h, stdbool.h, stdint.h és tgmath.h) a C99(wd), a C-szabvány 1999-ben közzétett módosításával, további öt fájl (stdalign.h, stdatomic.h, stdnoreturn.h, threads.h és uchar.h) a C11(wd) 2011-ben, és még egy fájl (stdbit.h) a 2023-ban megjelent C23-mal(wd) került hozzá. Összesen most már 30 fejlécfájl van:

További információk Név, -tól ...

A fejlécfájlok közül három (complex.h, stdatomic.h és threads.h) olyan feltételes funkciókat tartalmaz, amelyeket az implementációknak nem kell támogatniuk.

A POSIX szabvány számos nem szabványos C fejléccel egészítette ki a Unix-specifikus funkciókat. Sokuk átkerült más architektúrákba is. Ilyen például az fcntl.h és az unistd.h. Számos más csoport más nem szabványos fejléceket is használ – a GNU C library rendelkezik az alloca.h-val, az OpenVMS pedig a va_count() függvénnyel.

Dokumentáció

Unix-szerű rendszereken az API hiteles dokumentációja man-oldalak formájában érhető el. A legtöbb rendszeren a szabványos könyvtári függvényekről szóló man oldalak a 3. fejezetben találhatók; a 7. fejezet tartalmazhat néhány általánosabb lapot a mögöttes fogalmakról (pl. man 7 math_error Linuxon).

Remove ads

Megvalósítások

A Unix-szerű rendszerek általában rendelkeznek C könyvtárral megosztott könyvtár formájában, de a fejlécfájlok (és a fordító eszköztár) hiányozhatnak a telepítésből, így a C fejlesztés nem feltétlenül lehetséges. A C könyvtár a Unix-szerű rendszereken az operációs rendszer részének tekinthető; a C szabvány által meghatározott funkciók mellett más, az operációs rendszer API-jának részét képező funkciókat is tartalmaz, például a POSIX szabványban meghatározott funkciókat. A C könyvtári függvényeket, beleértve az ISO C szabványos függvényeket is, a programok széles körben használják, és úgy tekintik őket, mintha nem csak a C nyelvben lévő valaminek az implementációját, hanem de facto az operációs rendszer interfészének a részét képeznék. A Unix-szerű operációs rendszerek általában nem tudnak működni, ha a C könyvtárat törlik. Ez azokra az alkalmazásokra igaz, amelyek dinamikusan, nem pedig statikusan linkeltek. Továbbá maga a kernel (legalábbis a Linux esetében) könyvtáraktól függetlenül működik.

A Microsoft Windows rendszerben az alaprendszer dinamikus könyvtárai (DLL-ek) a Microsoft Visual C++(wd) v6.0 fordítóhoz tartozó C szabványkönyvtár implementációját biztosítják; a Microsoft Visual C++ fordító újabb verzióihoz tartozó C szabványkönyvtárat az egyes fordítók külön-külön, valamint az újraforgalmazható (redistributable) csomagok biztosítják. A C nyelven lefordított alkalmazásokat vagy statikusan összekapcsolják egy C könyvtárral, vagy a könyvtár dinamikus verziójával likelik, amelyet az alkalmazásokkal együtt szállítanak, ahelyett, hogy arra támaszkodnának, hogy a célrendszereken jelen legyen. A fordító C könyvtárában található függvények nem tekinthetők a Microsoft Windows interfészének.

Számos C könyvtár implementáció létezik, amelyeket különböző operációs rendszerek és C fordítóprogramok egyaránt biztosítanak. A népszerű implementációk közül néhány a következő:

  • A libc(wd), a BSD-alapú operációs rendszerekkel együtt terjesztett különböző implementációk
  • GNU C library (glibc), amelyet a GNU Hurd(wd), GNU/kFreeBSD, és a legtöbb Linux disztribúció használ
  • Microsoft C futásidejű könyvtár, a Microsoft Visual C++(wd) része. A könyvtárnak két változata létezik: Az MSVCRT, amely a v12 / Visual Studio 2013-ig újraosztható volt, alacsony C99-megfelelőséggel, és egy új, UCRT (Universal C Run Time), amely a Windows 10 és 11 része, így mindig jelen van a linkeléshez, és szintén C99-kompatibilis .
  • dietlibc(wd), a C szabványos könyvtár egy alternatív kis implementációja (MMU nélküli)
  • μClibc(wd), egy C szabványú könyvtár beágyazott μClinux(wd) rendszerekhez (MMU nélkül)
    • uclibc-ng, egy beágyazott C könyvtár, a μClibc elágazása, továbbra is karbantartott, memóriakezelő egység (MMU) támogatással
  • Newlib(wd), beágyazott rendszerekhez készült C szabványos könyvtár (MMU nélkül)[8] és a Cygwin GNU Windows disztribúcióban használatos
  • klibc(wd), elsősorban Linux rendszerek indításához
  • musl(wd), egy másik könnyített C szabványos könyvtár implementáció Linux rendszerekre[9]
  • Bionic(wd), eredetileg a Google által az Android beágyazott operációs rendszerhez fejlesztett, a BSD libc-ből származik.
  • picolibc, Keith Packard(wd) által kifejlesztett, kis beágyazott rendszereket céloz meg, korlátozott RAM-mal, a Newlib(wd) és az AVR Libc kódján alapul

Fordítók beépített függvényei

Egyes fordítóprogramok (például a GCC[10]) a C szabványos könyvtár számos függvényének beépített változatát biztosítják; azaz a függvények implementációi a lefordított object-fájlba kerülnek, és a program a beépített változatokat hívja meg a C könyvtár megosztott objektumfájljában lévő függvények helyett. Ez csökkenti a függvényhívások többletköltségét, különösen, ha a függvényhívásokat inline(wd) változatokkal helyettesítjük, és lehetővé teszi az optimalizálás más formáit (mivel a fordító ismeri a beépített változatok vezérlés-áramlási(wd) jellemzőit), de zavarokat okozhat a hibakeresés során (például a beépített változatok nem helyettesíthetők instrumentált változatokkal).

A beépített függvényeknek azonban úgy kell viselkedniük, mint az ISO C szabványnak megfelelő közönséges függvényeknek. A fő következmény az, hogy a programnak képesnek kell lennie arra, hogy a függvények címét átvéve mutatót hozzon létre ezekre a függvényekre, és ezen mutató segítségével hívja meg a függvényt. Ha a program két különböző fordítási egységében ugyanarra a függvényre mutató két mutatót származtatunk, akkor a két mutatónak egyenlőnek kell lennie, azaz a cím a függvény nevének feloldásával jön létre, amely külső (programszintű) hivatkozással rendelkezik.

Linking, libm

A FreeBSD[11] és a glibc[12] alatt néhány függvény, például a sin() alapértelmezés szerint nincs linkelve, helyette a libm matematikai könyvtárba van csomagolva. Ha bármelyiküket használjuk, a linkernek meg kell adni a -lm direktívát. A POSIX megköveteli, hogy a c99 fordító támogassa az -lm opciót, és hogy a math.h, complex.h és fenv.h fejlécekben deklarált függvények elérhetőek legyenek a linkeléshez, ha a -lm opciót megadjuk, de azt nem írja elő, hogy a függvények alapértelmezés szerint linkelve legyenek.[13] A musl úgy tesz eleget ennek a követelménynek, hogy mindent egyetlen libc könyvtárba helyez, és egy üres libm-et biztosít.[14]

Detektálás

A C szabvány szerint a __STDC_HOSTED__ makrót 1-re kell definiálni, ha az implementáció hosztolt. A hosztolt implementáció rendelkezik a C-szabvány által meghatározott összes fejléccel. Az implementáció lehet szabadonálló (freestanding) is, ami azt jelenti, hogy ezek a fejlécek nem lesznek jelen. Ha a megvalósítás önálló, akkor a freestanding __STDC_HOSTED__ értékét 0-ra kell definiálni.

Remove ads

Problémák és megoldások

Puffer túlcsordulási sebezhetőségek

A C szabványos könyvtár néhány függvénye az elfogadásuk óta hírhedt arról, hogy puffertúlcsordulási sebezhetőségeket tartalmaznak, és általában hibás programozásra ösztönöznek.[15][16] A legtöbbet kritizált tételek a következők:

  • a string-manipulációs rutinok, beleértve a strcpy() és strcat() programokat, a határok ellenőrzésének (bounds checking(wd)) hiánya és a lehetséges puffertúlcsordulás miatt, ha a határokat nem ellenőrzik manuálisan;
  • string rutinok általában, mellékhatások(wd), felelőtlen pufferhasználat ösztönzése, nem mindig érvényes null végződésű(wd) kimenet garantálása, lineáris hosszszámítás;[17]
  • printf() rutincsalád, a call stack elrontására, ha a formázott karakterlánc nem felel meg a megadott argumentumoknak. Ez az alapvető hiba a támadások egy egész osztályát hozta létre: a formázott karakterlánc-támadásokat(wd);
  • gets() és scanf() I/O rutinok családja, a bemeneti hossz ellenőrzésének (bármilyen, akár egyszerű) hiánya miatt.

A gets() extrém esetét kivéve, minden biztonsági rés elkerülhető a memóriakezelést, a korlátok ellenőrzését, a bemeneti ellenőrzést stb. végző segédkód bevezetésével. Ez gyakran olyan wrapper formájában történik, amely biztonságosabbá és könnyebben használhatóvá teszi a szabványos könyvtári függvényeket. Ez már B. Kernighan és R. Pike The Practice of Programming című könyvében is megjelenik, ahol a szerzők általában olyan wrappereket használnak, amelyek hibaüzeneteket írnak ki, és hiba esetén kilépnek a programból.

Az ISO C bizottság közzétette a TR 24731-1[18] műszaki jelentést, és jelenleg a TR 24731-2-n[19] dolgozik, hogy ennek megfelelően javaslatot tegyen néhány határérték-ellenőrzéssel és automatikus pufferelosztással rendelkező függvény elfogadására. Az előbbi komoly kritikát kapott, némi dicsérettel,[20][21] az utóbbi pedig vegyes visszhangot váltott ki.

Az aggályok ellenére a TR 24731-1-et az ISO/IEC 9899:2011 (C11) K. mellékletébe (Bounds-checking interfaces) integrálták a C-szabványok közé, és megközelítőleg a Microsoft C/++ futásidejű (CRT) könyvtárában implementálták a Win32 és Win64 platformokra.

(Alapértelmezés szerint a Microsoft Visual Studio C és C++ fordítói figyelmeztetést adnak ki, ha régebbi, „nem biztonságos” függvényeket használnak. A Microsoft TR 24731-1 implementációja azonban finoman szólva is inkompatibilis mind a TR 24731-1-gyel, mind a K melléklettel,[22] így a hordozható projekteknél gyakori, hogy letiltják vagy figyelmen kívül hagyják ezeket a figyelmeztetéseket. Közvetlenül kikapcsolhatók a következő módon:

#pragma warning(disable : 4996)

a kérdéses site[s] hívás előtt/körül, vagy közvetve

#define _CRT_SECURE_NO_WARNINGS 1

fejlécek hozzáadása előtt.[23] (A /D_CRT_NO_SECURE_WARNINGS=1 parancssori opciónak ugyanolyan hatást kell kifejtenie, mint ennek a #define-nek.)

Problémák a futási folyamatokkal kapcsolatban, sebezhetőség a versenyfeltételekkel szemben

A strerror() rutint kritizálják, hogy nem szálbiztos(wd) és egyébként sebezhető a versenyfeltételekkel szemben.

Hibakezelés

A C szabványos könyvtár függvényeinek hibakezelése nem következetes és néha zavaros. A Linux kézikönyv math_error oldala szerint: „A jelenlegi (2.8-as verzió) helyzet a glibc alatt kusza. A legtöbb (de nem minden) függvény hiba esetén kivételt (exception) okoz. Egyesek errno-t is beállítanak. Néhány függvény beállítja az errno-t, de nem vált ki kivételt. Nagyon kevés függvény egyiket sem teszi.”[24]

Remove ads

Szabványosítás

Az eredeti C nyelv nem rendelkezett beépített funkciókkal, például I/O műveletekkel, ellentétben a hagyományos nyelvekkel, mint például a COBOL és a Fortran. Idővel a C felhasználói közösségek megosztották egymással az ötleteket és a ma C szabványos könyvtáraknak nevezett implementációkat. Ezen ötletek közül sok végül beépült a szabványosított C nyelv meghatározásába.

Mind a Unix, mind a C az AT&T Bell Laboratories-ban született az 1960-as évek végén és az 1970-es évek elején. Az 1970-es években a C nyelv egyre népszerűbbé vált. Számos egyetem és szervezet kezdte el létrehozni a nyelv saját változatát saját projektjeihez. Az 1980-as évek elejére nyilvánvalóvá váltak a különböző C implementációk közötti kompatibilitási problémák. 1983-ban az Amerikai Nemzeti Szabványügyi Intézet (ANSI) létrehozott egy bizottságot, hogy létrehozza a C szabványos specifikációját „ANSI C(wd) néven. Ez a munka 1989-ben az úgynevezett C89 szabvány létrehozásában csúcsosodott ki. Az így létrejött szabvány része volt egy szoftverkönyvtárakból álló készlet, amelyet ANSI C szabványkönyvtárnak neveztek el.

POSIX standard library

A POSIX, valamint a SUS(wd) számos olyan rutint határoz meg, amelyeknek az alapvető C szabványos könyvtáron túlmenően is rendelkezésre kell állniuk. A POSIX specifikáció fejlécfájlokat tartalmaz többek között a többszálú futás(wd), a hálózatépítés(wd) és a reguláris kifejezések számára. Ezeket gyakran a C szabványos könyvtár funkcionalitása mellett valósítják meg, különböző fokú közelséggel. Például a glibc a libc.so-ban olyan funkciókat valósít meg, mint a fork, de mielőtt az NPTL-t(wd) beolvasztották volna a glibc-be, az egy külön könyvtár volt, saját linker flag argumentummal. Gyakran ezt a POSIX-specifikált funkciót a könyvtár részének tekintik; az alapvető C könyvtárat ANSI vagy ISO C könyvtárként azonosítják.}

BSD libc

A BSD libc' a POSIX szabványos könyvtár egy szuperhalmaza, amelyet a BSD operációs rendszerekhez, például a FreeBSD, NetBSD, OpenBSD és macOS operációs rendszerekhez tartozó C könyvtárak támogatnak. A BSD libc tartalmaz néhány olyan bővítményt, amelyet az eredeti szabvány nem definiál, és amelyek közül sok először az 1994-es 4.4BSD kiadásban jelent meg (az első, amelyet nagyrészt az első szabvány 1989-es kiadása után fejlesztettek ki). A BSD libc néhány bővítménye a következő:

  • sys/tree.h  tartalmazza a red–black tree és a splay tree(wd)[25] implementációját[26][27]
  • sys/queue.h  láncolt lista, queue, hátsó várólista (tail queue) stb. megvalósításai[28][29]
  • fgetln()  definiált az stdio.h-ban. Ez egy fájl soronkénti olvasására használható.[30][31][32]
  • fts.h  tartalmaz néhány függvényt a fájlhierarchia bejárásához[33][34]
  • db.h  néhány funkció a Berkeley DB-hez(wd) való csatlakozáshoz[35][36]
  • strlcat() és strlcpy()  az strncat() és strncpy() biztonságos alternatívái[37][38][39][40][41]
  • err.h  tartalmaz néhány függvényt formázott hibaüzenetek nyomtatására[42][43]
  • vis.h  tartalmazza a vis() függvényt. Ez a függvény a nem nyomtatható karakterek vizuális formában történő megjelenítésére szolgál.[44][45][46]
Remove ads

A C szabványkönyvtár más nyelveken

Egyes nyelvek a C szabványos könyvtár funkcióit saját könyvtáraikba foglalják. A könyvtárat a nyelv struktúrájához jobban hozzáigazíthatják, de a működési szemantika hasonló marad.[47]

C++

A C++ nyelv a C szabványos könyvtár konstrukcióinak többségét beépíti a sajátjába, kivéve a C-specifikus műveleteket. A C szabványos könyvtár függvényei kétféleképpen exportálhatók a C++ szabványos könyvtárból.

A C-vel és a szabvány előtti C++-szal való visszafelé/keresztkompatibilitás érdekében a függvények a globális névtérben (::) érhetők el, a C szabványos fejlécnév beolvasása (#include-ing) után, mint a C-ben.[48] Így a C++98 program:

#include <stdio.h>
int main() {
    return ::puts("Hello, world!") == EOF;
}

a C95(wd) programmal (látszólag) azonos viselkedést kell mutatnia

#include <stdio.h>
int main(void) {
    return puts("Hello, world!") == EOF;
}

A C++98-tól kezdve a C függvények a ::std névtérben is elérhetővé válnak (pl. a C printf mint C++ ::std::printf, az atoi mint ::std::atoi, a feof mint ::std::feof), a megfelelő C fejléc <hdrname.h> helyett a <chdrname> fejléc beépítésével. Pl. <cstdio> helyettesíti az <stdio.h>-t és <cmath> az <math.h>-t; vegye figyelembe a .h kiterjesztés hiányát a C++ fejlécneveknél.

Így a fenti két programmal egyenértékű (általában előnyösebb) C++≥98 program a következő:

#include <cstdio>
int main() {
    return std::puts("Hello, world") == EOF;
}

Egy using namespace ::std deklaráció a main felett vagy a main-on belül automatikusan alkalmazza a ::std:: előtagot, bár általában rossz gyakorlatnak számít globálisan használni a fejlécekben, mert ez szennyezi a globális névteret.[49]

A C fejlécek közül néhány C++≥98 verzió hiányzik; például a C≥11 <stdnoreturn.h> és <threads.h> fejléceknek nincs C++ megfelelője.[50]

Mások helyőrzőkké redukálódnak, mint például (a C++20-ig(wd)) a <ciso646> a C95 <iso646.h> számára, amelynek minden szükséges makrója kulcsszóként jelenik meg a C++98-ban. A C-specifikus szintaktikai konstrukciók általában nem támogatottak, még akkor sem, ha a fejlécük támogatott.[51]

Számos C fejléc elsősorban a C++ kompatibilitás miatt létezik, és ezek általában közel üresek a C++-ban. Például, a C99-17 <stdbool.h> csak a következőre van szükség:

#define bool _Bool
#define false 0
#define true 1
#define __bool_true_false_are_defined 1

hogy a C++98 bool, false és true kulcsszavak támogatását színlelje a C-ben. A C++11 a kompatibilitás érdekében megköveteli a <stdbool.h> és a <cstdbool> fájlokat, de csak az __bool_true_false_are_defined-et kell definiálniuk. A C23(wd) elavulttá teszi a régebbi _Bool kulcsszót az új, C++98-nak megfelelő bool, false és true kulcsszavak javára, így a C≥23 és a C++≥11 <stdbool.h>/<cstddbool> fejlécek teljesen egyenértékűek. (Különösen a C23 nem igényel semmilyen __STDC_VERSION_BOOL_H__ makrót a <stdbool.h> számára).

A C könyvtári függvények elérését lehetőség szerint a ::std névtéren és a C++≥98 fejlécneveken keresztül kell előnyben részesíteni. Az elfogadás ösztönzése érdekében a C++98 eltörli a C (*.h) fejlécneveket, így lehetséges, hogy a C kompatibilis fejlécek használata egy különösen szigorú C++98-20 preprocesszort valamilyen diagnosztikai hibaüzenetre késztet. A C++23 azonban (szokatlan módon) törli ezeket a fejléceket, így az újabb C++ implementációknak/módoknak nem kellene panaszkodniuk anélkül, hogy külön kérnénk őket.[52]


Más nyelvek hasonló megközelítést alkalmaznak, és a C kompatibilis függvényeket/rutinokat egy közös névtér alá helyezik; ezek közé tartozik a D, a Perl és a Ruby.

Python

A CPython a C könyvtár néhány függvényének burkolatát tartalmazza a saját közös könyvtárában, és közvetlenebb hozzáférést biztosít a C függvényekhez és változókhoz a ctypes csomagon keresztül.[53]

Általánosabban, a Python 2.x úgy határozza meg a beépített fájlobjektumokat, mint amelyek „a C stdio csomagjának felhasználásával vannak implementálva”[54], és gyakran hivatkozik a C szabványos könyvtár viselkedésére; a rendelkezésre álló műveletek (open, read, write stb.) várhatóan ugyanúgy viselkednek, mint a megfelelő C függvények (fopen, fread, fwrite stb.).

A Python 3 specifikációja azonban jóval kevésbé támaszkodik a C-specifikációra, mint a Python 2.

Rust

A Rust a crate libc-t kínálja, amely lehetővé teszi a különböző C szabványos (és egyéb) könyvtári függvények és típusdefiníciók használatát.[55]

Remove ads

Összehasonlítás más nyelvek szabványos könyvtáraival

A C szabványkönyvtár kicsi néhány más nyelv szabványkönyvtárához képest. A C könyvtár matematikai függvények alapkészletét, karakterlánc-kezelést, típuskonverziókat, valamint fájl- és konzol-alapú I/O-t biztosít. Nem tartalmaz olyan szabványos „konténertípusokat(wd), mint a C++ szabványos sablonkönyvtár, nem is beszélve a teljes grafikus felhasználói felület (GUI) eszközkészletről, hálózati eszközökről és egyéb funkciók sokaságáról, amelyeket a Java és a .NET Framework szabványosan biztosít. A kis szabványos könyvtár fő előnye, hogy a működő ISO C környezet biztosítása sokkal könnyebb, mint más nyelvek esetében, és ennek következtében a C program új platformra történő átvitele viszonylag egyszerű.

Remove ads

Jegyzetek

Loading content...

További információk

Loading content...

Fordítás

Loading related searches...

Wikiwand - on

Seamless Wikipedia browsing. On steroids.

Remove ads