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 szabványból kiindulva, a C POSIX könyvtárral 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 (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 , 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 2011-ben, és még egy fájl (stdbit.h
) a 2023-ban megjelent C23-mal került hozzá. Összesen most már 30 fejlécfájl van:
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++ 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 , 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 , GNU/kFreeBSD, és a legtöbb Linux disztribúció használ
- Microsoft C futásidejű könyvtár, a Microsoft Visual C++ 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 , a C szabványos könyvtár egy alternatív kis implementációja (MMU nélküli)
- μClibc , egy C szabványú könyvtár beágyazott μClinux 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 , 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 , elsősorban Linux rendszerek indításához
- musl , egy másik könnyített C szabványos könyvtár implementáció Linux rendszerekre[9]
- Bionic , eredetileg a Google által az Android beágyazott operációs rendszerhez fejlesztett, a BSD libc-ből származik.
- picolibc, Keith Packard által kifejlesztett, kis beágyazott rendszereket céloz meg, korlátozott RAM-mal, a Newlib é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 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 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()
ésstrcat()
programokat, a határok ellenőrzésének (bounds checking ) 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 , felelőtlen pufferhasználat ösztönzése, nem mindig érvényes null végződésű 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 ;gets()
ésscanf()
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 é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” 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 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 , a hálózatépítés é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 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[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 azstdio.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 való csatlakozáshoz[35][36]strlcat()
ésstrlcpy()
– azstrncat()
ésstrncpy()
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 avis()
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 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 ) 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 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” , 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
További információk
Fordítás
Wikiwand - on
Seamless Wikipedia browsing. On steroids.
Remove ads