Programski jezik C
Prográmski jêzik C ali kar C (izgovorjava [cé] ali po izvirniku [sí]) je nizkonivojski imperativni standardizirani računalniški programski jezik tretje generacije (3GL) za splošno rabo. Podpira strukturalno programiranje, leksično območje spremenljivk in rekurzijo, statični sistem tipov pa preprečuje mnogo nenameravanih operacij. Zasnova jezika C omogoča konstrukte, ki se učinkovito preslikujejo v tipične strojne ukaze, in zaradi tega se je C začel rabiti v aplikacijah, ki so bile prej razvite v zbirnem jeziku, še posebej v sistemskem programju, kot je npr. računalniški operacijski sistem Unix,[4] kot tudi v različnem uporabniškem programju za računalnike od superračunalnikov do vgradnih sistemov.
Programski jezik C je prvotno razvil Dennis Ritchie med letoma 1969 in 1973 v AT&T Bellovih laboratorijih.[5][6][7] Ritchie in Ken Thompson sta najprej razvila prevajalnik za operacijski sistem Unix, ki je bil v osnovi napisan v zbirnem jeziku. Unixovo jedro je bilo tako prvo napisano v drugem jeziku in ne v zbirnem. Kasneje se je C hitro pojavil tudi na drugih operacijskih sistemih.
Pred uradnim standardom za C se je mnogo uporabnikov in izvršiteljev opiralo na neuradno specifikacijo, opisano v knjigi Programski jezik C Briana Kernighana in Ritchieja. Ta različica je v splošnem znana kot »K&R« C. Leta 1989 je Ameriški državni inštitut za standarde (ANSI) objavil standard za C (v splošnem imenovan »ANSI C« ali »C89«). Naslednje leto je to specifikacijo potrdila Mednarodna organizacija za standardizacijo (ISO) kot mednarodni standard (v splošnem imenovan »C90«). ISO je kasneje izdala razširitev standarda za podporo internacionalizacije leta 1995 in popravljeni standard (znan kot »C99«) leta 1999. Ta standard je do sedaj najbolj razširjen. Trenutna različica standarda (sedaj imenovana »C11«) je ISO kot ISO/IEC 9899:2011 potrdila 8. decembra 2011.[8]
Zasnova
[uredi | uredi kodo]C je imperativni (proceduralni) jezik. Izdelan je bil za prevajanje na relativno preprostem prevajalniku in da bi zagotavljal nizkonivojski dostop do pomnilnika, jezikovne konstrukte, ki bi se učinkovito preslikali v tipične strojne ukaze in, da bi potreboval najmanjšo podporo izvajanja. Zaradi tega se C začel rabiti v mnogih aplikacijah, ki so bile prej razvite z zbirnem jeziku, še posebej v sistemskem programiranju.
Navkljub svojim nizkonivojskim zmožnostim se je jezik C razvil v smislu boljšega programiranja na mnogih platformah. Program zapisan v C, ki je v skladu s standardom in napisan prenosljivo, se lahko prevede za zelo širok nabor računalniških platform in operacijskih sistemov z zelo malo spremembami v izvorni kodi. Tako je C postal razpoložljiv na mnogih platformah od vgrajenih mikrokrmilnikov do superračunalnikov.
C velja za učinkovit jezik in je primeren za sistemska opravila, ni pa najprimernejši za učenje programiranja, čeprav se pogosto pojavlja v izobraževanju. Je tudi eden od najbolj razširjenih programskih jezikov, skupaj z javo, C++ ali PHP, od leta 2008 pa mu priljubljenost celo rahlo narašča.[9][10] Obstaja zelo malo arhitektur in operacijskih sistemov za katere ni na voljo prevajalnika za C. C se veliko rabi tudi za razvoj prenosljivega uporabniškega programja.[4]
Pregled in osnovne značilnosti jezika
[uredi | uredi kodo]Kot večina imperativnih jezikov v tradiciji ALGOLa je C zmožen strukturalnega programiranja in omogoča leksično območje spremenljivk ter rekurzijo, statični sistem tipov pa preprečuje mnogo nenameravanih operacij.
C je dokaj skop programski jezik, ki deluje blizu strojne opreme, in je za razliko od večine programskih jezikov bolj podoben zbirniku. Včasih ga imenujejo »prenosljivi zbirnik«, kar tudi označuje njegovo pomembno razliko od zbirniškega jezika. Izvorno kodo, napisano v C, se da prevesti in pognati na skoraj vsakem stroju. Tega ne zmore skoraj noben obstoječ programski jezik in tudi kodo, zapisano v zbirniku, se lahko požene le na določenih vrstah strojev. C po navadi imenujejo nizkonivojski ali srednjenivojski jezik, kar označuje kako blizu strojne opreme lahko deluje.
V C-ju je vsa izvršna koda vsebovana znotraj podprogramov, imenovanih »funkcije«, čeprav ne v strogem pomenu funkcionalnega programiranja. Parametri funkcij se vedno prenašajo po vrednosti. Prenos po sklicu se v C simulira z eksplicitnim prenašanjem vrednosti kazalcev. Izvorno besedilo programa v C je v prostem formatu in za končnik stavkov rabi podpičje (;
), ter zavita oklepaja ({ }
) za združevanje blokov stavkov.
C so naredili zaradi enega samega pomembnega namena, kar ni slučajnost, da bi bilo moč pisati velike programe z manj napakami v proceduralnem programiranju in, da pisec programov ne bi nosil bremena tvorjenja prevajalnika za C, ki ga otežujejo zapleteni gradniki jezika. V tem smislu ima C naslednje pomembne značilnosti:
- majhno fiksno število rezerviranih besed, ki vključuje polno množico primitivov nadzornega pretoka:
for
,if/else
,while
,switch
indo/while
. Obstaja en imenski prostor, imena, ki jih opredeli uporabnik, se ne morejo razlikovati od rezerviranih besed z nobeno vrsto sigle, - veliko število aritmetičnih, logičnih (eniških, dvojiških, trojiških) in pozapisnih operatorjev, kot so npr.:
+
,-
,!
,*
,&
,~
,+=
,++
,<<
,? :
,.
,->
ipd., - v enem stavku se lahko izvede več kot ena prireditev,
- preprost sistem podatkovnih tipov, ki obvaruje pred brezpredmetnimi operacijami,
- slovarsko področje spremenljivk,
- tipizacija je statična, vendar prisiljeno šibka: vsi podatki imajo tip, lahko pa se izvede implicitno pretvarjanje. Znaki se lahko na primer rabijo kot cela števila,
- usmeritev na proceduralno programiranje z zmožnostjo programiranja v slogu strukturalnega programiranja,
- označitvena skladnja posnema kontekst rabe. C nima rezervirane besede »define« in se namesto tega stavek, ki se začne z imenom tipa, vzame kot označitev. Ne obstaja rezervirana beseda »function«, namesto tega je funkcija naznačena z oklepajema, ki objemata seznam njenih parametrov,
- uporabniško definirani tipi (
typedef
) in sestavljeni tipi,- naštevni tipi (enumerated types) z rezervirano besedo
enum
. Niso opremljeni z označbami in so prosto medsebojno spremenljivi s celimi števili, - zapisi ali skupki raznovrstnih podatkovnih tipov (
struct
), ki jih določi uporabnik, in omogočajo združevanje in upravljanje podobnih podatkovnih elementov v celoti, - indeksiranje polj je sekundarni zapis, definiran s pomočjo kazalčne aritmetike. Z razliko od unij, polja niso prvorazredni objekti – ni jih moč prirediti ali primerjati s pomočjo posameznih vgrajenih operatorjev. Pri rabi ali opredelitvi ne obstaja rezervirana beseda »array«. Namesto tega oglata oklepaja (
[ ]
) nakazujeta polja skladenjsko, na primermesec[11]
, - znakovni nizi niso posebni podatkovni tip, ampak so po navadi izvedeni kot ničelno omejena polja znakov z nadzornim ničelnim znakom
'\0'
,[a]
- naštevni tipi (enumerated types) z rezervirano besedo
- uporaba predprocesorskega jezika, predprocesorja C, za naloge kot so določevanje makrojev, vključevanje večkratnih datotek z izvorno kodo in pogojno prevajanje,
- nizkonivojski nepreverjeni dostop do računalniškega pomnilnika s pomočjo pretvorbe strojnih naslovov v tipske kazalce,[b]
- parametri, ki prehajajo v funkcije po vrednosti in ne po sklicu (referenci),
- kadar se ne rabi, se lahko vrednost vračanja funkcije prezre,
- podprogrami, ki ne vračajo vrednosti, so posebni primer funkcij z netipskim vrnitvenim tipom
void
. - funkcije se ne morejo opredeliti znotraj slovarskega področja drugih funkcij.
- kazalci na funkcije, ki omogočajo osnovno obliko zaprtja (closure) in izvajalnega polimorfizma,
- osnovna oblika modularnosti: datoteke se lahko prevedejo samostojno in povežejo skupaj, z nadzorom katere funkcije in podatkovni objekti so vidni v drugih datotekah prek atributov
static
aliextern
, - zelo omejena raba ukaza
else
(načelo KISS). - preprost jedrski jezik s pomembno kompleksno funkcionalnostjo, kot na primer upravljanje V/I nalog in delo z znakovnimi nizi, matematične funkcije ali delo z datotekami omogočajo knjižniški podprogrami,
C ne vsebuje nekaterih gradnikov, ki so sestavni deli novejših, sodobnejših visokonivojskih jezikov, kot na primer objektne usmerjenosti ali samodejnega čiščenja pomnilnika, tako da ima ročno upravljanje pomnilnika.
Povezave z drugimi jeziki
[uredi | uredi kodo]Razvoj jezika C je zelo vplival na druge programske jezike, še posebej na C++, ki se je razvil kot razširitev C-ja. Mnogo kasnejših jezikov si je neposredno ali posredno sposodilo določene gradnike C-ja, na primer: D, Go, Rust, java, JavaScript, Limbo, LPC, C#, Objective-C, Perl, PHP, Python, Swift, Vala, Verilog (strojni opisni jezik),[3] in Unixova C shell. Ti jeziki so dobili mnogo svojih nadzornih struktur in drugih osnovnih gradnikov od C-ja. Večina od njih, kjer je Python največja izjema, je tudi skladenjsko zelo podobnih C-ju v splošnem in so usmerjeni na združevanje prepoznavnih izrazov in stavkov skladnje jezika C z osnovo sistemov tipa, podatkovnih modelov in semantiko, ki je lahko popolnoma drugačna. Skladnja pri teh jezikih včasih vključuje tudi enakovredne preproste nadzorne strukture.[12][c][13][14][d] C++ in Objective-C sta bila na začetku jezika prevajalnikov, ki so tvorila kodo v C. C++ je trenutno skoraj supermnožica C,[15] Objective-C pa je stroga supermnožica C.[16][17][18] C se rabi tudi kot posredni jezik za druge jezike[19] ter za ustvarjanje standardnih knjižnic in izvajalnih sistemov za višjenivojske jezike, kot je npr. CPython.[20]
Razvoj
[uredi | uredi kodo]Zgodnji razvoj
[uredi | uredi kodo]Izvor jezika C je tesno povezan z razvojem operacijskega sistema Unix, ki so ga izvirno razvili v zbirnem jeziku na miniračunalniku DEC PDP-7 Ritchie, Thompson, Joe Ossana, Rudd Canaday in Doug McIlroy v AT&T Bellovih laboratorijih, in vključili več zamisli svojih kolegov.[21] V začetku Thompson niti ni programiral na samem PDP-7, ampak je rabil množico makrojev za zbirni jezik GEMAP na 32-bitnem osrednjem stroju General Electric GE-635. Nato je poprocesor tvoril papirni trak, ki ga je PDP-7 lahko prebiral.[6] Kmalu je Unix s preprostim jedrom, zbirnim jezikom, preprosto lupino (tolmačem ukazov) in z nekaterimi pripomočki (kot npr. Unixovi ukazi rm
, cat
, cp
) leta 1969 postal samozadosten, in razvoj se je lahko nadaljeval neodvisno na samem PDP-7. Douglas McIlroy je kmalu zatem tvoril prvi visokonivojski jezik sistema Unix, izvedbo prevajalnika prevajalnikov TMG Roberta M. McClurea. McIlroy in Bob Morris sta uporabila TMG za zgodnji prevajalnik jezika PL/I v operacijskem sistemu Multics. Thompson se je zaradi McIlroyjevega uspeha reproduciranja TMG odločil, da je Unix, ki verjetno tedaj še ni bil imenovan tako, potreboval lasten sistemski programski jezik.
Pisanje v zbirnem jeziku novo nastalega Unixa je bilo nerodno. Za pisanje programskih struktur se je porabilo več časa, kodo je bilo težje razhroščevati in jo razumeti.[22] Thomson je želel imeti prednosti visokonivojskega jezika vendar ne v smislu operacijskega sistema Multics, napisanega v PL/I in zbirnem jeziku. Bil je vodja neformalne skupine v AT&T, ki je začela pregledovati možnosti drugih operacijskih sistemov in višjenivojskih jezikov. Najprej je s pomočjo TMG leta 1970 neuspešno hotel uporabiti Fortran[23], nato pa je ustvaril jezik B s poenostavitvijo raziskovalnega jezika BCPL, ki ga je leta 1967 razvil Martin Richards, tako da je lahko njegov tolmač šel v 8 kB 18-bitni besedni pomnilnik računalnika PDP-7.
B se je izkazal za zelo počasnega in nezmožnega za sistemsko programiranje v samem Unixu. Tako kot BCPL je bil brez tipov. Pri novem zmogljivejšem računalniku DEC PDP-11 je bil jezik brez tipov neizvršljiv. Njegov procesor je podpiral podatkovne tipe različnih velikosti in z jezikom B tega ni bilo moč izraziti. Problem je bilo tudi izvajanje. Thompson in Ritchie sta se odločila prenesti operacijski sistem na PDP-11. Prva različica PDP-11 je imela 16 kB pomnilnika za operacijski sistem in 8 kB za uporabniške programe.[21] Tudi njegov operacijski sistem je bil napisan v zbirnem jeziku. Želela sta napisati operacijski sistem v jeziku B. Najprej je zaradi nezmožnosti rabe nekaterih prednosti računalnika PDP-11, še posebej bajtno naslovljivost, v letu 1971 nastal »novi B« (NB), ki je rešil te probleme.[24] Ta jezik se je kmalu razvil in preimenoval (leta 1972) v C. Postal je prevajalni in ne tolmačitveni jezik.
Začetni razvoj jezika C je po Ritchiejevih besedah potekal v AT&T Bellovih laboratorijih med letoma 1969 in 1973[6]. Najbolj kreativno obdobje je bilo leta 1972. Tedaj je bila večina Unixa ponovno napisana v C-ju.[25] Do leta 1973 z dodatkom podatkovnega tipa zapisov struct
je C postal dovolj močan za prevod Unixovega jedra. Novi jezik je dobil ime »C«, ker so bili njegovi gradniki izvedeni iz jezika »B«, ta pa je bil po Thompsonovih besedah okleščena različica jezika BCPL.[26]
Tako je bilo Unixovo jedro prvo jedro kakšnega operacijskega sistema napisano v drugem jeziku od zbirnega. Pred tem sta bila na primer še operacijska sistema Multics (napisan v PL/I) in MCP (Master Control Program) za sistem Burroughs B5000 (napisan v ALGOLu leta 1961.) Leta 1977 sta Ritchie in Stephen Curtis Johnson dodatno spremenila jezik C za pospešitev prenosljivosti operacijskega sistema Unix. Johnsonov Portable C Compiler (PCC) je služil kot osnova za več izvedb C-ja na novih platformah.[27]
K&R C
[uredi | uredi kodo]Leta 1978 sta Kernighan in Ritchie objavila prvo izdajo knjige Programski jezik C (The C Programming Language).[28] Ta knjiga, pri programerjih v C-ju znana kot »bela knjiga« (white book), oziroma »K&R«[6], je bila mnogo let neformalna specifikacija jezika. Različica jezika C, ki ga knjiga opisuje, se navadno imenuje K&R C. Druga izdaja knjige[28] pokriva kasnejši standard ANSI C.
K&R je uvedla nekaj jezikovnih gradnikov:
- standardna V/I knjižnica
- podatkovni tip
long int
- podatkovni tip
unsigned int
- sestavljeni prireditveni operatorji v obliki
=
op (kot npr.=-
) so spremenjeni v obliko op=
zaradi semantične dvoumnosti pri tvorjenju takšnih konstruktov kot npr.i=-10
, kar je bilo tolmačeno koti =- 10
(zmanjšaji
za vrednost 10) namesto možno predvidenegai = -10
(priredii
vrednost -10)
Tudi po objavi standarda C leta 1989, je K&R C še vedno mnogo let veljal za »najmanjši skupni imenovalec« na katerega so se programerji v C-ju omejili, kadar je bila žaželena največja možna prenosljivost, saj je bilo v rabi še vedno več starejših prevajalnikov, skrbno napisana koda v K$R C pa je bila lahko tudi veljavni standard za C.
V zgodnejših različicah C-ja je bilo treba pred opredelitvijo (definicijo) uvesti le funkcije, ki so vračale vrednosti razen tipov int
. Funkcija, ki se je rabila brez predhodne označitve (deklaracije), je privzeto vračala vrednosti int
, če se je njena vrednost uporabila. Na primer:
long neka_funkcija();
/* int */ druga_funkcija();
/* int */ klicna_funkcija()
{
long test1;
register /* int */ test2;
test1 = neka_funkcija();
if (test1 > 0)
test2 = 0;
else
test2 = druga_funkcija();
return test2;
}
Določilnike tipa int
, ki so izpuščeni, v K&R C ni bilo treba navajati, kasnejši standardi pa so jih zahtevali.
Ker označitev funkcij v K&R C ni vsebovala nobenega podatka o parametrih funkcije, njihovo preverjanje ni bilo izvedeno, čeprav je nekaj prevajalnikov javljalo opozorilno sporočilo, če je bila lokalna funkcija klicana z napačnim številom parametrov, ali, če je več klicev zunanje funkcije rabilo različno število tipov parametrov. Razvili so več ločenih orodij, kot na primer Unixov pripomoček lint
, ki so poleg drugih stvari lahko preverjala doslednost rabe funkcij križem v več datotekah izvorne kode.
Po objavi K&R C so k jeziku dodali več gradnikov, ki so jih podpirali prevajalniki, na primer od AT&T (še posebej PCC[29]) in od nekaterih drugih ponudnikov. Med njimi so:
- funkcije
void
(funkcije, ki ne vračajo vrednosti) - funkcije, ki vračajo podatkovne tipe
struct
aliunion
(namesto kazalcev) - prireditev za podatkovne tipe
struct
- naštevni tipi (enumerated types)
Veliko število razširitev, pomanjkanje dogovora o standardni knjižnici, priljubljenost jezika in dejstvo, da tudi na operacijskem sistemu Unix prevajalniki niso dosledno izvrševali specifikacije K&R, je vodilo do potrebe za standardizacijo.
ANSI C in ISO C
[uredi | uredi kodo]V poznih 1970-ih in 1980-ih so izvedli različice C-ja za širok razpon osrednjih računalnikov, miniračunalnikov in mikroračunalnikov, vključno z osebnim računalnikom IBM PC, saj se je tedaj njegova priljubljenost zelo povečala.
Leta 1983 je Ameriški državni inštitut za standarde (ANSI) ustanovil odbor X3J11 za ustanovitev standardne specifikacije jezika C. X3J11 je osnoval standard za C na Unixovi izvedbi; vendar so neprenosljivi del Unixove knjižnice C predali delovni skupini 1003 IEEE, ki je postala osnova za standard POSIX leta 1983. Leta 1989 so standard C potrdili kot ANSI X3.159-1989 »Programming Language C«. Ta različica jezika se po navadi imenuje ANSI C, Standard C ali včasih C89.
Leta 1990 je standard ANSI C (z oblikovnimi spremembami) sprejela Mednarodna organizacija za standardizacijo (ISO) kot ISO/IEC 9899:1990, kar se včasih imenuje C90. Tako se izraza »C89« in »C90« nanašata na isti programski jezik.
Kakor druge nacionalne ustanove za standarde ANSI ni več razvijal standarda C neodvisno, ampak ga je odložil k mednarodnemu standardu C, ki ga vzdržuje delovna skupina ISO/IEC JTC1/SC22/WG14. Nacionalna usvojtev posodobitve mednarodenga standarda se po navadi izvede še v letu publikacije ISO.
Eden od ciljev procesa standardizacije jezika C je bilo tvorjenje supermnožice K&R C, ki bi vključevala več predhodno uvedenih neuradnih gradnikov. Standardizacijski odbor je vključil tudi več dodatnih gradnikov, kot so npr. prototipi funkcij (izposojeno od C++), kazalci void
, podpora za mednarodni nabor znakov in lokalnih parametrov, ter predprocesorske izboljšave. Čeprav je bila skladnja za označitev parametrov povečana, da bi vključevala slog rabljen v C++, je bil vmesnik K&R zaradi združljivosti z obstoječo izvorno kodo še naprej dovoljen.
C89 podpirajo trenutni prevajalniki za C, večina kode v C-ju, ki je zapisana sedaj, temelji na njem. Vsak program, zapisan le v ANSI C in brez privzetkov odvisne strojne opreme, se bo izvajal pravilno na katerikoli platformi v skladu z izvedbo C-ja v mejah svojih virov. Brez takšnih previdnosti se lahko programi prevedejo le na določenih platformah ali z določenim prevajalnikom zaradi na primer rabe nestandardnih knjižnic, kot so knjižnice grafičnih uporabniških vmesnikov, ali oslonitev na računalniške ali specifične platformske atribute, kot je točna velikost podatkovnih tipov in ureditev bajtov (endianness).
V primerih, ko mora biti koda prevedljiva tako v skladu s standardom ali s prevalniki na osnovi K&R C, se lahko rabi makro __STDC__
, ki razdeli kodo na dele z ANSI C in K&R, ter tako prepreči prevajalnikom na osnovi K&R C uporabo gradnikov, razpoložljivih le v ANSI C.
Po standardizacijskem procesu ANSI/ISO je specifikacija jezika C več let ostala statična. Leta 1995 so k standardu C iz leta 1990 dodali Normative Amendment 1 (ISO/IEC 9899/AMD1:1995, neformalno znan kot C95). Z njim so popravili nekaj podrobnosti in dodali obsežnejšo podporo mednarodnega nabora znakov.
C99
[uredi | uredi kodo]Standard C so v poznih 1990-ih na novo popravili, kar je leta 1999 vodilo do objave standarda ISO/IEC 9899:1999, ki je v splošnem znan kot »C99«. Od tedaj so ga s tehniškimi popravki dopolnili trikrat.[30]
C99 je uvedel več novih gradnikov. Na primer znotrajvrstične funkcije (inline functions), nove podatkovne tipe (na primer long long int
in complex
za delo s kompleksnimi števili), polja s spremenljivo dolžino (variable-length arrays (VLA)), izboljšano podporo aritmetike s plavajočo vejico IEEE 754, podporo variarnih makrojev (variadic macros, makrojev s spremenljivo arnostjo) in podporo enovrstičnih komentarjev, ki se začnejo z dvema poševnicama //
, kot v BCPL ali C++. Več teh gradnikov je kot razširitve tedaj že podpiralo nekaj prevajalnikov za C.
C 99 je večinoma nazaj združljiv s C90, vendar je na nekaterih mestih strožji. Še posebej, označitev, ki je brez določilnika tipa, implicitno privzeto ni več tipa int
. Standardni makro __STDC_VERSION__
je določen z vrednostjo 199901L
in nakazuje, da je na voljo podpora C99. GCC, Solaris Studio in drugi prevajalniki za C sedaj podpirajo mnogo ali pa vse nove gradnike C-ja v standardu C99. Prevajalnik za C v Microsoft Visual C++ izpolnjuje standard C89 in tiste dele C99, ki so zahtevani za združljivost z različico standarda C++11.[31]
C11
[uredi | uredi kodo]Leta 2007 so se začela dela na novi različici standarda C, ANSI C11 ali ISO/IEC 9899:2011, do objave 8. decembra 2011 neformalno imenovane »C1X«. Standardizacijski odbor je sprejel smernice za omejitev usvojitve novih gradnikov, ki jih niso preskusili z obstoječimi izvedbami.
V standardu C11 se je pojavilo več novih gradnikov jezika C in knjižnic, na primer: makroji rodovnih tipov, anonimne strukture, izboljšana podpora kodirnega standarda Unicode, atomske operacije, mnogonitnost in funkcije s preverjanjem mej. Neketeri deli obstoječe knjižnice C99 so postali izbirni, izboljšana je bila tudi združljivost s C++. Standardni makro __STDC_VERSION__
je definiran kot 201112L
in tako označuje, da je na voljo podpora standardu C11.
Vgradni C
[uredi | uredi kodo]Programiranje z vgradnim C-jem (embedded C) zgodovinsko zahteva nestandardne razširitve k jeziku C, da se lahko podpirajo C-ju tuji gradniki, kot so npr.: aritmetika s fiksno vejico, mnogokratne različne pomnilniške vrstice in osnovne V/I operacije.
Leta 2008 je standardizacijski pododbor SC 22 objavil tehniško poročilo z razširitvijo jezika C,[32] ki se je nanašala na probleme med razširitvami jezika C za različne vgradne sisteme, in tako zagotovila splošni standard za vse ustrezne izvedbe. Vključuje več gradnikov, ki v normalnem C niso na voljo: aritmetika s fiksno vejico, prostori z imenovanimi naslovi in osnovno V/I naslavljanje strojne opreme.
Vgradni C rabi večino skladnje in semantike standardnega C-ja: funkcija main
, opredelitev spremenljivk, označitev podatkovnih tipov, pogojni stavki (if
, switch
, case
), zanke (while
, for
), funkcije, polja in znakovni nizi, strukture in unije, bitne operacije, makroji ipd.
Skladnja
[uredi | uredi kodo]C ima formalno slovnico, ki jo določa standard C.[33] Z razliko od nekaterih drugih jezikov, kot je npr. FORTRAN 77, je izvorna koda C-ja proste oblike, kjer se znaki za prazni prostor lahko rabijo poljubno, koda pa ni odvisna od stolpčnih ali besedilno-vrstičnih omejitev. Meje vrstic so drugače med predprocesorsko fazo pomembne.
Komentarji
[uredi | uredi kodo]Komentarji so lahko med razmejilnima znakoma /*
in */
enovrstično ali mnogovrstično, od standarda C99 naprej pa tudi za razmejilnima znakoma //
enovrstično do konca vrstice. Komentarji, ki jih razmejujeta /*
in */
, ne smejo biti vgnezdeni. Če se zaporedje teh dveh znakov pojavi znotraj znakovnega niza ali znakovnega črkovnega simbola, se ne obravnavata kot razmejilna znaka komentarja.[28] Komentarji oblike:
/* ... */
/*
...
*/
/* ... // ... */
// ...
/*
... // ...
*/
so v redu, vgnezdeni enovrstično pa npr. ne:
/* /* ... */ ... */
ali vgnezdeni mnogovrstično:
/*
/* ...
*/ ...
*/
saj drugo zaporedje /*
ne velja za razmejilni znak komentarja, kot tudi ne drugo zaporedje */
, ki je sedaj zunaj komentarja, in prevajalnik bi v obeh primerih javil napako.
Izrazi
[uredi | uredi kodo]Datoteke s C-jevsko izvorno kodo vsebujejo označitev (deklaracijo) in opredelitev (definicijo) funkcij. Opredelitve funkcij po vrsti vsebujejo označitve in stavke. Označitve opredeljujejo nove podatkovne tipe z rezerviranimi besedami, kot so: struct
, union
in enum
, ali prirejajo tipe in morda rezervirajo pomnilniška mesta novim spremenljivkam, po navadi z zapisom tipa, ki mu sledi ime spremenljivke. Rezervirane besede, kot sta char
in int
, označujejo vgrajene tipe. Deli kode so obdani z zavitima oklepajema {
in }
, ki omejujeta označitveno področje ali pa delujeta kot samostojni stavek za nadzorne strukture.
C kot imperativni jezik za označitev dejanj rabi stavke. Najbolj razširjeni stavek je izrazni stavek, ki vsebuje izraz, kateremu je treba določiti vrednost, izrazu pa sledi podpičje. Zaradi še večje preglednosti se podpičje velikokrat razmakne od označitvenih/ukaznih besed z dodatnim presledkom. Na primer:
int a; | int a ;
for (i=0; i<max; i++) | for (i = 0 ; i < max ; i++)
Kot stranski pojav določitve vrednosti se funkcije lahko kličejo in spremenljivkam se lahko priredijo nove vrednosti. Za spreminjanje normalne zaporedne izvršitve stavkov ima C več stavkov za nadzor toka, ki jih označujejo rezervirane besede. Strukturalno programiranje je podprto s pogojno izvršitvijo if
(-else
), z iterativnimi izvršitvami (zankami) if
(-else
), while
in for
. Stavek for
ima ločene dodelitvene izraze, izraze za preverjanje in izraze za ponovno dodelitev – vsak od njih pa se lahko opusti. Izraza break
in continue
se lahko rabita za zapustitev najbolj notranjega zančnega stavka ali za preskočitev na njeno ponovno dodelitev. Obstaja tudi nestrukturalni stavek goto
, ki preusmerja neposredno na imenovano oznako znotraj funkcije. switch
izbere primer, ki se izvede na podlagi vrednosti celoštevilskega izraza.
Izrazi lahko rabijo različne vgrajene operatorje in lahko vsebujejo klice funkcij. Vrstni red po katerem se določijo vrednosti parametrom funkcij in operandom večine operatorjev ni določen. Določevanje vrednost je lahko tudi vloženo vmes. Vendar se bodo vsi stranski vplivi (vključno s pomnilnikom do spremenljivk) pojavili pred naslednjo »zaporedno točko«. Zaporedne točke vsebujejo zaključek vsakega izraznega stavka ter vstop in vračanje iz vsakega klica funkcije. Zaporedne točke se pojavijo tudi med določevanjem vrednosti izrazov, ki vsebujejo določene operatorje (&&
, ||
, ?:
in operator vejica). To dovoljuje visoko stopnjo optimizacije kode prevajalnika, vendar od programerjev v C zahteva večjo skrb za dosego zanesljivih rezultatov kot je potrebna pri drugih programskih jezikih.
Kernighan in Ritchie v uvodu knjige Programski jezik C pravita: »Kakor drugi jeziki ima C svoje hibe. Nekateri od operatorjev imajo napačno prednost; nekateri deli skladnje bi lahko bili boljši.«[35] Standard C ni poskušal popraviti veliko od teh hib zaradi vpliva takšnih sprememb na že obstoječo programsko opremo.
Nabor znakov
[uredi | uredi kodo]Osnovni nabor znakov izvorne kode jezika C vsebuje:
- neštevilske znake:
- 26 velikih in 26 majhnih angleških latiničnih črk iz standardnega nabora ASCII:
A
,B
,C
,D
,E
,F
,G
,H
,I
,J
,K
,L
,M
,N
,O
,P
,Q
,R
,S
,T
,U
,V
,W
,X
,Y
,Z
a
,b
,c
,d
,e
,f
,g
,h
,i
,j
,k
,l
,m
,n
,o
,p
,q
,r
,s
,t
,u
,v
,w
,x
,y
,z
- podčrtaj:
_
- številske znake:
- 10 desetiških števk:
0
1
2
3
4
5
6
7
8
9
- 10 desetiških števk:
- dodatnih 28 grafičnih znakov:
! " # % & ' ( ) * + , - . / : ; < = > ? [ \ ] ^ { | } ~
- znake za prazni prostor (whitespace): presledek, vodoravni tabulator, navpični tabulator, pomik na novo stran, nova vrstica (newline)
Nova vrstica označuje konec vrstice besedila. Ni treba da odgovarja dejanskemu posameznemu znaku, čeprav je v C zaradi prikladnosti to posamezen znak.
Lahko se rabijo tudi dodatni mnogobitno zakodirani znaki v prikazu znakovnih nizov, vendar niso povsem prenosljivi. Zadnji standard za C (C11) dovoljuje mnogonacionalne znake kodirnega standarda Unicode, ki so prenosljivo lahko del besedila izvorne kode C s pomočjo kodiranj \uXXXX
ali \UXXXXXXXX
, kjer X
označuje šestnajstiško zapisan znak. Ta možnost še ni v široki rabi.
Osnovni izvršni nabor znakov C obsega enake znake, skupaj s prikazom opozorila (alert), povratnega znaka (backspace) in pomika na začetek vrstice (carriage return). Podpora izvajalnemu času za razširjene nabore znakov se je z vsako različico standarda za C povečevala.
Rezervirane besede
[uredi | uredi kodo]Naslednje besede (keywords; reserved words) so v jeziku C rezervirane in imajo strog pomen kot posamezni znaki (tokens).[36][8] Ne smejo se na novo opredeliti ali se rabiti kot identifikatorji v drugih kontekstih:
|
|
Besede so občutljive na male ali velike črke. INT
, INt
, InT
, Int
, iNT
, iNt
ali inT
na primer ni enako kot int
. V različnih izvedbah prevajalnikov za C se lahko pojavijo tudi druge rezervirane besede, npr. ada
, asm
, fortran
, pascal
, čeprav se tam običajno nestandardne besede začnejo z enim ali dvema podčrtajema, npr. __asm
, _Cdecl
ipd.[37] V primerjavi z drugimi velikimi jeziki ima C majhno število rezerviranih besed. Ada jih ima na primer 62. Ena od značilnosti jezika C je, da lahko naredi veliko z relativno malo posebnimi simboli in rezerviranimi besedami.[36] Na začetku je imel C manj rezerviranih besed, na primer 29, sedaj pa jih pozna 44. Kasneje so bile dodane rezervirane besede, kot so: _Bool
, _Complex
, const
, _Imaginary
, inline
, restrict
, signed
in volatile
. Beseda entry
se ni nikoli rabila in sedaj ni več rezervirana.[28]
Operatorji
[uredi | uredi kodo]C podpira bogat nabor operatorjev, ki so simboli znotraj izraza za določevanje potrebnih opravil med njegovim izvajanjem. C ima operatorje za:
- aritmetiko:
+
,-
,*
,/
,%
- prireditev:
=
- povečano prireditev:
+=
,-=
,*=
,/=
,%=
,&=
,|=
,^=
,<<=
,>>=
- bitno logiko:
~
,&
,|
,^
- bitni pomik:
<<
,>>
- Booleovo logiko:
!
,&&
,||
- pogojno določitev vrednosti:
? :
- primerjanje enakosti:
==
,!=
- klicanje funkcij:
( )
- povečanje in zmanjšanje:
++
,--
- izbiro elementa:
.
,->
- velikost objekta:
sizeof
- relacije urejenosti:
<
,<=
,>
,>=
- referenco in dereferenco:
&
,*
,[ ]
- vrstni red:
,
- združevanje podizrazov:
( )
- pretvorbo tipov:
(typename)
C rabi operator =
, ki je v matematiki rezerviran za izražanje enakosti, za naznanitev prireditve po zgledu predhodnih jezikov Fortrana in PL/I, vendar z razliko od ALGOLa in njegovih izpeljank. Podobnost med cejevskima operatorjema za prireditev in za primerjanje enakosti (==
) so kritizirali, saj se ju lahko preprosto zamenja. V mnogih primerih mora biti vsak rabljen v kontekstu drugega brez napak prevajalnika, čeprav nekateri prevajalniki tvorijo opozorila. Pogojni izraz v if(a=b+1)
je pravilen, če a
ni enak nič po prireditvi.[38] Poleg tega operatorska prednost ni intuitivna, saj se operator ==
zvezuje tesneje kot operatorja &
in |
v izrazih, kot je x & 1 == 0
, ki bi moral biti zapisan kot (x & 1) == 0
za pravilno določitev vrednosti.[39]
Zgradba, oblika programa in slog v C
[uredi | uredi kodo]Osnovni gradnik programa v C je funkcija.[40] Vsak program v C je zbirka ene ali več funkcij. Funkcije sestavljajo označitve spremenljivk in stavki, ali zapleteni ukazi, obkrožata pa jih zavita oklepaja ({
in }
).
Zgleda programov
[uredi | uredi kodo]Program Pozdravljen, svet
[uredi | uredi kodo]Spodnji zgled izpiše znakovni niz »Pozdravljen svet!« na standardni izhod. Navadno je standardni izhod povezan z zaslonom monitorja, lahko pa je tudi datoteka ali kakšna druga strojna naprava. Program je napisan v skladu s standardom ANSI C.
#include <stdio.h>
int main(void)
{
printf("Pozdravljen svet!\r\n");
return 0;
}
Sledi analiza programa po vrsticah:
#include <stdio.h>
Prva vrstica v programu je predprocesorski ukaz (navodilo, direktiva) #include
. Pred samim prevajanjem programa predprocesor pregleda izvorno kodo in izvrši vse predprocesorske ukaze. Ti ukazi se vedno začnejo z znakom #
. Ukaz #include
povzroči, da se na njegovo mesto v izvorno kodo vključi datoteka stdio.h
, ki vsebuje standardne vhodno izhodne funkcije.
int main(void)
V naslednji vrstici se opredeli funkcija z imenom main
. Ta funkcija ima poseben pomen v C programih. Pri začetku izvajanja programa se najprej kliče ta funkcija. Ključna beseda int
na začetku vrstice pove, da funkcija main()
vrne celo število, ključna beseda void
pa, da funkcija ne sprejme nobenih parametrov. Funkcija main
po standardu ANSI C vedno vrača vrednost, čeprav nekateri prevajalniki prevedejo kodo uspešno, četudi temu ni tako. Tudi v jeziku C++ je ta funkcija še vedno C-jevska. Funkcija main
je lahko opredeljena s pomočjo naslednjih štirih oblik ob označitvi:[41][e][f][g]
int main() { /* ... */ }
int main(void) { /* ... */ }
int main(int argc, char *argv[]) { /* ... */ }
int main(int argc, char **argv) { /* ... */ }
oziroma prototipno:
int main();
int main(void);
int main(int, char *[]);
int main(int, char **);
Prvi dve opredelitvi sta enakovredni (in združljivi s C++).
{
Odprti zaviti oklepaj pomeni začetek opredelitve funkcije main
.
printf("Pozdravljen svet!\r\n");
V tej vrstici se kliče funkcija printf
, ki je označena v datoteki stdio.h
. Pri tem klicu se funkciji printf
poda en parameter v obliki znakovnega niza. Na koncu znakovnega niza je še posebni dvoznakovni niz \n
, ki se prevede v znak EOL (end of line). Znak je namenjen kot ukaz izhodni napravi, da postavi trenutno lego na začetek naslednje vrstice.
return 0;
Vrstica zaključi izvajanje funkcije main
in vrne celo število 0.
}
Zaprti zaviti oklepaj pomeni zaključek opredelitve funkcije main
.
Najmanjši program
[uredi | uredi kodo]Katera opredelitev funkcije main
se uporabi v programu, je verjetno odvisno od posamezne izbire. Trenutni standard C vsebuje dva zgleda rabe main()
in dva main(void)
, standard C++ pa rabi main()
. Vrednost, ki jo main
vrača (in mora biti tipa int
), služi kot status prekinitve. Tega program vrne gostiteljevemu okolju.
Standard C definira vrnitveni vrednosti 0
(»nič napak« (zero errors)) in EXIT_SUCCESS
, ki označujeta uspeh, ter EXIT_FAILURE
za označevanje neuspešnega izvajanja programa. (EXIT_SUCCESS
in EXIT_FAILURE
sta opredeljeni v standardni zaglavni datoteki stdlib.h
). Druge vrnitvene vrednosti služijo kot izvedbeni opredelitveni pomeni. V Linuxu na primer program, ki ga je prekinil ukaz signal, vrne kodo številske vrednosti signala plus 128.
Najmanjši pravilen program v C vsebuje prazno funkcijo main
brez parametrov:
int main(void){}
Lahko se zapiše tudi v več vrsticah:
int main(void)
{ /* začetek telesa funkcije v prvem stolpcu vrstice */
}
ali redkeje sicer v skladu z dobrim slogom:
int /* podatkovni tip vrnjene vrednosti funkcije */
main(void) /* ime funkcije v prvem stolpcu vrstice */
{ /* začetek telesa funkcije v prvem stolpcu vrstice */
}
Sploh pa je slaba praksa pisati neporavnano, kot npr:
int
main
/*
**
* * * **/ (
void
)
{ }
ali:
int
main/*
** * * *
**/(void){ }
oziroma poravnano brez reda:
int main /*
** * *
***/ ( void
) { }
Preveden program bo sicer deloval, izvorna koda pa je že v preprostem zgledu nepregledna. Seveda je treba rezervirane besede, imena spremenljivk in funkcij pisati brez presledkov.
Okrogla oklepaja (), ki sledita imenu funkcije, morata biti vključena, saj na ta način C razlikuje funkcije od navadnih spremenljivk. Načeloma pri funkcijah za imenom funkcije in odprtim oklepajem ni presledka, npr. main(void)
in ne main (void)
, z razliko od sizeof ()
, ki dejansko strogo ni funkcija, in je skladenjska rezervirana beseda za enočleni operator.[42] sizeof
je lahko podobno kot return
brez okroglih oklepajev. Pri return
je to celo zaželeno, razen če je dvoumno.
Ker nista navedena return
ali exit
, funkcija main
ob izhodu vrne 0.[43] To je poseben primer predstavljen v standardu C99, ki velja le za funkcijo main
. Če se zahteva še ta navedba, ima najmanjši program obliko:
int main(void) { return 0; }
Funkcija main
bo za uspešno delovanje programa po navadi klicala druge funkcije. Ni treba, da je na vrhu programa, tako da se program v C ne začne v prvi vrstici, ampak tam kjer je navedena funkcija main
.[40] Funkcije main
ni možno klicati ali jo zagnati s kakšno drugo funkcijo v programu. Kliče jo lahko le operacijski sistem in na ta način se zažene program v C. Funkcija main
ni nikoli statična, in, če je navedena kot static int main()
, bo prevajalnik običajno javil napako.
Nekatere izvedbe niso izvedljive, po navadi zaradi tega, ker niso mišljene za rabo z operacijskim sistemom. Takšne izvedbe se v standardu C imenujejo prostostoječe (free-standing). V prostostoječi izvedbi ni podrobnega opisa kako naj obravnava izvajanje programa. V programu še posebej ni treba opredeliti funkcije main
.
Druge funkcije se lahko imenujejo poljubno v skladu s skladnjo jezika. Lahko jih napiše programer sam ali pa se rabijo obstoječe iz knjižnic. Vmesniki za knjižniške funkcije so običajno navedeni z vključitvijo zaglavnih datotek s preprocesorsko direktivo #include
, objekti knjižnice pa se povežejo v končno izvršno sliko. Določene knjižniške funkcije, kot sta na primer printf
ali scanf
, so definirane s standardom C, in se imenujejo standardne knjižniške funkcije.
Funkcija lahko vrne vrednost klicatelju - po navadi drugi funkciji C-ja, ali gostiteljevemu okolju za funkcijo main
. Zgoraj omenjena funkcija printf
vrne koliko znakov je bilo izpisano, vendar se ta vrednost običajno prezre.
Podatkovni tipi
[uredi | uredi kodo]C ima statični šibki sistem tipov, ki je deloma podoben potomcem ALGOLa, kot je npr. paskal, vendar C sam ni potomec Algola.[44] V C obstajajo vgrajeni tipi za cela števila različnih velikosti, tako predznačena in nepredznačena, števila s plavajočo vejico (npr. racionalna števila), znake in naštevne tipe (enum
). C99 je z rezervirano besedo _Bool
dodal Booleov podatkovni tip (Booleova spremenljivka). Obstajajo tudi izpeljani tipi, kot so: polja (tabele, arrays), kazalci, zapisi (struct
) in nenaznačene unije (union
).
C se velikokrat rabi v programiranju nizkonivojskih sistemov, kjer morda ni potrebe za sistemom tipov. Prevajalnik poskuša zagotoviti pravilnost tipov večine izrazov, vendar lahko programer zaobide preverbe na več načinov, ali s pomočjo opustitve tipov (type cast), kjer ekscplicitno pretvori vrednost iz enega tipa v drugega, ali s pomočjo kazalcev ali unij, kjer se osnovni biti podatkovnega objekta na novo tolmačijo na kakšen drug način.
Za nekatere je označitvena skladnja v C neintuitivna, še posebej kazalci na funkcije. (Richiejeva zamisel je bila, da se določilniki označijo v kontekstu njihove rabe: »označitev zrcali rabo.«)[28]
C-jevske običajne aritmetične pretvorbe dovoljujejo tvorjenje učinkovite kode, vendar lahko včasih pride do nepričakovanih rezultatov. Primerjava predznačenih in nepredznačenih celih števil enale širine na primer zahteva pretvorbo predznačene vrednosti v nepredznačeno. To lahko povzroči nepričakovane rezultate, če je predznačena vrednost negativna.
Osnovni podatkovni tipi
[uredi | uredi kodo]V jeziku C je več osnovnih podatkovnih tipov. Večina od njih se tvori iz enega od štirih osnovnih aritmetičnih določilnikov tipov v C (char
, int
, float
in double
), ter štirih izbirnih določilnikov (signed
, unsigned
, short
in long
). Vsi razpoložljivi osnovni aritmetični tipi so navedeni v razpredelnici:
podatkovni tip in sopomenke |
pojasnilo | mejne vrednosti v limits.h
|
formatno določilo |
---|---|---|---|
char |
najmanjša naslovljiva enota stroja, ki lahko vsebuje osnovni nabor znakov. Njen tip je celoštevilski. Dejanski tip je lahko predznačen ali nepredznačen, kar je odvisno od izvedbe. Vsebuje CHAR_BIT bitov in je njegov obseg [−128, +127]. |
CHAR_MIN , CHAR_MAX |
%c
|
signed char |
enaka velikost kot char , vendar je zagotovo predznačena in je njegov obseg [−128, +127]. |
SCHAR_MIN , SCHAR_MAX |
%c (ali %hhi za numerični vnos)
|
unsigned char |
enaka velikost kot char , vendar je zagotovo nepredznačena. V dvojiškem zapisu je predstavljen brez zapolnjevalnih bitov, tako je njegov obseg točno [0, 2CHAR_BIT −1],[45] običajno [0, +255] |
UCHAR_MAX |
%c (ali %hhu za numerični vnos)
|
short short int signed short signed short int |
predznačeni celoštevilski tip short. Njegov obseg je vsaj [−32768, +32767],[46] in zato je njegova velikost vsaj 16 bitov. | SHRT_MIN , SHRT_MAX |
%hi
|
unsigned short unsigned short int |
podobno kot short , vendar nepredznačeno, in je njegov obseg vsaj [0, +65535]. |
USHRT_MAX |
%hu
|
int signed signed int |
osnovni predznačeni celoštevilski tip. Njegov obseg je vsaj [−32768, +32767],[46] in zato je njegova velikost vsaj 16 bitov. | INT_MIN , INT_MAX |
%i ali %d
|
unsigned unsigned int |
podobno kot int , vendar nepredznačeno, in je njegov obseg vsaj [0, +65535]. |
UINT_MAX |
%u
|
long long int signed long signed long int |
predznačeni celoštevilski tip long. Njegov obseg je vsaj [−2147483648, +2147483647],[46] in zato je njegova velikost vsaj 32 bitov. | LONG_MIN , LONG_MAX |
%li ali %ld
|
unsigned long unsigned long int |
podobno kot long , vendar nepredznačeno, in je njegov obseg vsaj [0, +4294967295]. |
ULONG_MAX |
%lu
|
long long long long int signed long long signed long long int |
predznačeni celoštevilski tip long long. Njegov obseg je vsaj [−9223372036854775808, +9223372036854775807],[46] in zato je njegova velikost vsaj 64 bitov. Uveden s standardom C99. | LLONG_MIN , LLONG_MAX |
%lli ali %lld
|
unsigned long long unsigned long long int |
podobno kot long long , vendar nepredznačeno, in je njegov obseg vsaj [0, +18446744073709551615]. Uveden s standardom C99. |
ULLONG_MAX |
%llu
|
float |
tip za števila s plavajočo vejico in enojno točnostjo. Dejanske značilnosti niso navedene (razen spodnjih mej), vendar je na večini sistemov to dvojiški format števila s plavajočo vejico in enojno točnostjo IEEE 754. Ta format zahteva izbirni Annex F »IEC 60559 floating-point arithmetic.« | FLT_MIN , FLT_MAX |
%f (samodejno razglašen na double v funkciji printf() )
|
double |
tip za števila s plavajočo vejico in dvojno točnostjo. Dejanske značinosti niso navedene (razen spodnjih mej), vendar je na večini sistemov to dvojiški format števila s plavajočo vejico in dvojno točnostjo IEEE 754. Ta format zahteva izbirni Annex F »IEC 60559 floating-point arithmetic.« | DBL_MIN , DBL_MAX |
%f (%lf za funkcijo scanf() )
|
long double |
tip za števila s plavajočo vejico in razširjeno točnostjo. Dejanske značilnosti niso navedene. Z razliko od tipov float in double je lahko 80-bitni format s plavajočo vejico, »double-double«, ki ni v skladu z IEEE ali dvojiški format števila s plavajočo vejico in štirikratno točnostjo IEEE 754, če je format s povišano točnostjo zagotovljen, drugače je enako kot double . Za podrobnosti glej članek o long double. |
LDBL_MIN , LDBL_MAX |
%Lf
|
Dejanska velikost celoštevilskih tipov se v izvedbah razlikuje. Standar zahteva le velikostne povezave med podatkovnimi tipi in najmanšimi vrednostmi za vsak podatkovni tip:
Zahteve za povezave so, da long long
ni manjši od long
, ki ni manjši od int
, ta pa ne manjši od short
. Ker je velikost char
vedno najmanjši podprti podatkovni tip, vsi drugi podatkovni tipi ne morejo biti manjši.
Najmanjša velikost za char
je 8 bitov, najmanjši velikosti za short
in int
sta 16 bitov, za long
32 bitov in za long long
mora vsebovati vsaj 64 bitov.
Tip int
mora biti celoštevilski tip, za katerega je ciljni procesor najbolj učinkovit. To omogoča veliko prilagodljivost, saj so lahko na primer vsi tipi 64-bitni. Vendar je priljubljeno več različnih shem celoštevilskih širin (podatkovnih modelov). To je zato ker podatkovni model definira kako različni programi med seboj komunicirajo, enotni podatkovni model se rabi znotraj uporabniškega vmesnika danega operacijskega sistema.[47]
Treba je omeniti, da je v praksi velikost tipa char
po navadi 8 bitov, tipa short
pa 16 bitov (kakor tudi njihova nepredznačena dvojnika). To velja za platforme pogoste v 1990-ih, kot so: SunOS 4 Unix, Microsoft MS-DOS, sodobni Linux in Microchip MCC18 za vgradne 8-bitne mikrokontrolerje PIC. POSIX zahteva, da je velikost char
točno 8 bitov.
Tudi dejanska velikost in obnašanje tipov s plavajočo vejico se razlikuje v izvedbah. Edino zagotovilo je, da long double
ni manjši od double
, ki ni manjši od float
. Če ju strojna oprema podpira, se po navadi rabita 32-bitna in 64-bitna dvojiška formata s plavajočo vejico IEEE 754.
Kazalci
[uredi | uredi kodo]C podpira rabo kazalcev, vrsto sklica, ki zapisuje naslov ali mesto objekta ali funkcije v pomnilniku. Naslov objekta je odvisen od sistema. Kazalci v C so izpeljani podatkovni tipi in se lahko dereferencirajo za dostop podatkov, ki so shranjeni na naslovu na katere kažejo, ali kličejo funkcije na katere kažejo. S kazalci se lahko upravlja s pomočjo prirejanja ali kazalčne aritmetike. Predstavitev vrednosti kazalca pri izvajanju je običajno surov pomnilniški naslov (mogoče povečan z izravnavo znotraj besedilnega polja), vendar ker kazalčni tip vsebuje tip objekta na katerega kaže, se lahko izrazi, ki vključujejo kazalce, preverijo glede na tip že med prevajanjem. Kazalčna aritmetika se samodejno skalira z velikostjo podatkovnega tipa na katero se kaže.
Osnovna skladnja za opredelitev kazalca v C je:[48]
podatkovni_tip *ime_kazalca;
Na primer:
int *ptr;
To označi ptr
kot identifikator objekta naslednjega tipa:
- kazalec, ki kaže na objekt tipa
int
To se običajno navede bolj zgoščeno kot 'ptr
je kazalec na int
'. Pri tem znak »*« (zvezdica) pomeni unarni ali nomadski operator posrednosti (indirektnosti, indirection operator) ali dereferenčni operator (dereference operator).
Slogov zapisa kazalcev je lahko več. Na primer:
int* ptr;
int *ptr;
int * ptr;
Običajno se rabi zapis operatorja posrednosti brez presledka pred imenom kazalca int *ptr;
, predvsem zaradi nedvomljivosti pri hkratnih večkratnih opredelitvah:
int *ptr1, *ptr2, a, b;
Ker C ne opredeljuje implicitne dodelitve za objekte z avtomatičnim pomnilniškim trajanjem,[49] je treba biti velikokrat previden pri zagotavljanju, da je naslov, na katerega kaže ptr
, veljaven. Zaradi tega včasih predlagajo, da se kazalcu eksplicitno dodeli vrednost ničelnega kazalca (null pointer value), ki je v C tradicionalno določena s standardiziranim makrojem NULL
:[50]
int *ptr = NULL;
Sicer v tem primeru kazalec še ne 'kaže nikamor', razen da ima vrednost ničelnega kazalca. Pri tem je npr. izpis 'neobstoječe' vrednosti (ničelnega kazalca), kamor naj bi kazal kazalec v funkciji printf
s formatom izpisa podatkovnega tipa int %d
in formatom izpisa kazalcev %p
v redu, izpis 'praznega' naslova, pa ne:
printf("\n%d %p", ptr, ptr); /* program izpiše 0 in npr. (nil) */
printf("\n%p", *ptr); /* program javi napako sklica na naslov pomnilniškega mesta */
Vrednost ničelnega kazalca tako eksplicitno ne kaže na nobeno veljavno mesto v pomnilniku. Dereferenciranje njegove vrednosti je nedoločeno, kar velikokrat povzroča segmentacijsko odpoved (segmentation fault). Vrednosti ničelnih kazalcev so uporabne pri nakazovanju posebnih primerov, kot so brez »naslednjega« kazalca v končnem vozlišču povezanega seznama, ali kot naznanitev napake iz funkcij, ki vračajo kazalce. V ustreznih kontekstih izvorne kode, ko je prirejanje kazalčne spremenljivke, se lahko konstanta ničelnega kazalca zapiše kot 0
, z ali brez eksplicitne opustitve na tip kazalca, ali kot makro NULL
, ki je opredeljen v več standardnih zaglavnih datotekah. V pogojnih zvezah imajo vrednosti ničelnih kazalcev napačno vrednost, vse druge vrednosti kazalcev pa pravilno.
Kazalci se v C rabijo za več namenov. Z besedilnimi znakovnimi nizi se običajno upravlja s pomočjo kazalcev v polja znakov. Dinamična dodelitev pomnilnika se izvaja s kazalci. Veliko podatkovnih tipov, kot so na primer povezani seznami ali drevesa, je velikokrat izvedeno kot dinamično dodeljeni objekti struct
, ki so med seboj povezani s kazalci.
Kazalci na funkcije so uporabni za prenašanje funkcij kot parametrov funkcij višjega reda, kot na primer qsort ali bsearch, ali kot povratni klic (callback), ki ga izvedejo obdelovalniki dogodkov (event handlers).[43]
Prazni kazalci (void *
) kažejo na objekte nedoločenega tipa, in se lahko zaradi tega uporabijo kot »generični« podatkovni kazalci. Ker velikost in tip nakazanih objektov nista znana, se prazni kazalci ne morejo dereferencirati, in tudi kazalčna aritmetika nad njimi ni dovoljena, čeprav se lahko enostavno (in v mnogih zvezah so) pretvorjeni v in iz poljubnega tipa objektnega kazalca.[43]
Neprevidna raba kazalcev je potencialno nevarna. Ker se njihov tip ne preverja, lahko kazalčna spremenljivka kaže na poljubno mesto v pomnilniku, kar lahko povzroči nezaželene učinke. Čeprav pravilno rabljeni kazalci kažejo na varna mesta, lahko kažejo na nevarna mesta, če se zanje rabi nepravilna kazalčna aritmetika. Objekti na katera kažejo se lahko ponovno dodelijo in uporabijo (obviseli kazalci) – lahko se uporabijo brez, da bi se jim dodelila vrednost (divji kazalci), ali pa se jim lahko neposredno dodeli nevarno vrednost s pomočjo opustitve, unije ali prek drugega pokvarjenega kazalca. V splošnem C dopušča upravljanje in pretvarjanje med tipi kazalcev, čeprav običajno prevajalniki preskrbijo možnosti za različne nivoje preverjanja. Nekateri drugi programski jeziki te probleme rešujejo z bolj omejevalnimi tipi sklicev.
Polja
[uredi | uredi kodo]Podatkovni tipi polj imajo v C tradicionalno fiksno, statično velikost med prevajanjem. Standard C99 dovoljuje tudi obliko polj s sprememnljivo dolžino. Možno je tudi dodeliti blok pomnilnika (poljubne velikosti) pri izvajanju s pomočjo funkcije malloc
(calloc
) iz standardne knjižnice in ga obravnavati kot polje. Cejevska združitev polj in kazalcev pomeni, da so označena polja in ta dinamično dodeljena simulirana polja dejansko zamenljiva med seboj.
Ker se do polj (v bistvu) vedno dostopa prek kazalcev, se dostopi polj tipično ne preverjajo za vezano velikost polja, čeprav nekateri prevajalniki lahko preskrbijo preverjanje mej kot možnost.[51] Zaradi tega so možne prekršitve mej polj in te so kar vsakdanje v neprevidno napisani kodi. Lahko vodijo do različnih neugodnih stranskih pojavov, kot so: nepravilni dostopi do pomnilnika, popačenje podatkov, preplavljanje medpomnilnika in izjeme med izvajanjem. Če je zahtevano preverjanje mej, mora biti izvedeno ročno.
C nima posebnega predpisa za označitev mnogorazsežnih polj, in se raje zanaša na rekurzijo znotraj sistema tipov tako da označuje polja polj, ki učinkovito opravljajo enako stvar. Vrednosti indeksov nastalega »mnogorazsežnega polja« se lahko obravnava kot (linearno) povečevanje ureditve po vrsticah.
Mnogorazsežna polja se velikokrat rabijo v numeričnih algoritmih, večinoma iz uporabne linearne algebra za hranjenje podatkov matrik. Zgradba cejevskega polja je zo ta posebno nalogo zelo primerna. Ker se polja večinoma prenašajo kot kazalci, morajo biti njegove meje fiksne vrednosti ali drugače eksplicitno prenesene v poljubni podprogram, ki jih zahteva. Dinamično oblikovana polja polj se ne morejo dostopati s pomočjo dvojnega indeksiranja. To se lahko naredi z dodelitvijo polja z dodatnim »vrstičnim vektorjem« kazalcev k stolpcem.
Polje polje
se na primer lahko označi in uporabi na naslednje načine:
int polje[5]; /* označi 5 sosednjih celih števil */
int *vptr = polje; /* polja se lahko rabijo kot kazalci */
vptr[0] = 1; /* kazalci se lahko indeksirajo s skladnjo polj */
*(polje + 1) = 2; /* polja se lahko dereferencirajo s skladnjo kazalcev */
*(1 + polje) = 2; /* kazalčno seštevanje je komutativno */
2[polje] = 4; /* operator indeksa je komutativen */
Standard C99 je uvedel »polja s spremenljivo velikostjo«, ki rešujejo nekatere, vendar ne vse, probleme običajnih cejevskih polj.
Izmenljivost polj in kazalcev
[uredi | uredi kodo]Zapis s spuščenimi indeksi x[i]
(kjer x
označuje kazalec) je skladenjski sladkor za *(x+i)
.[52] S prednostjo pomnilnikovega znanja o kazalčnem tipu naslov, na katerega kaže x + i
, ni osnovni naslov (na katerega kaže x
), povečan za i
bitov, ampak je določen kot osnovni naslov, povečan z i
pomnoženim z velikostjo elementa, na katerega kaže x
. Tako x[i]
označuje i+1
-ti element polja.
V večini izraznih kontekstov, kjer je večja izjema operand sizeof
, se naprej ime polja samodejno pretvori v kazalec na prvi element polja. To pomeni, da se polje nikoli v celoti ne skopira, ko je imenovan kot parameter funkciji, ampak se prenese le naslov njegovega prvega elementa. Čeprav klici funkcij v C uporabljajo semantiko klicev po vrednosti, so tako polja učinkovito prenesena v sklicu.
Velikost elementa se lahko določi s pomočjo operatorja sizeof
na katerikoli dereferenciran element x
, kot v izrazu n = sizeof *x
ali n = sizeof x[0]
, tako, da se število elementov v označenem polju polje
lahko določi kot sizeof polje / sizeof polje[0]
. Zadnji izraz velja le za imena polj: spremenljivke označene s spuščenimi indeksi (int polje[20]
). Zaradi semantike C-ja ni mogoče določiti celotne velikosti polj prek kazalcev na polja ali polj tvorjenih z dinamično dodelitvijo (malloc
). Tako izrazi, kot je sizeof vptr / sizeof vptr[0]
(kjer vptr
označuje kazalec), ne bodo delovali, saj prevajalnik privzame, da se zahteva velikost kazalca samega.[53][54] Ker parametri imena polja na sizeof
niso pretvorjeni v kazalce, ne kažejo takšne nejasnosti. V polja tvorjena z dinamično dodelitvijo pa se dostopa s kazalci in ne kot prave spremenljivke polja, zato imajo enake težave z operatorjem sizeof
kot kazalci na polja. Če se v kakšni funkciji potrebuje vrednost velikosti (enorazsežnega) poljavptr
, jo je treba vključiti kot njen parameter (npr. velikost
). Na primer:
...
{
int *vptr = NULL;
static const int velikost = 10;
vptr = (int *) malloc(velikost * sizeof(vptr));
funkcija(vptr, velikost);
free(vptr);
...
}
funkcija(int *v, int n) /* funkcija ima (vsaj) dva parametra – kazalec na polje */
{ /* in njegovo velikost (n) */
...
}
Podobno velja za mnogorazsežna polja.
Navkljub tej navidezni enakosti med polji in kazalčnimi spremenljivkami je tako med njimi še vedno razlika. Čeprav se v večini izraznih kontekstih ime polja pretvori v kazalec (na njegov prvi element), kazalec sam ne zajema nobega dela pomnilnika – ime polja ni l-vrednost in njegov naslov je konstanta, z razliko od kazalčne spremenljivke. Zaradi tega se področje »na katerega kaže polje, ne more spremeniti, in na ime polja je nemogoče prirediti nov naslov. Vsebina polj pa se lahko kopira, na primer s pomočjo funkcije memcpy
ali z dostopanjem do posameznih elementov.
Upravljanje pomnilnika
[uredi | uredi kodo]Ena od najpomembnejših funkcij programskega jezika je zagotovitev pripomočkov za upravljanje pomnilnika in objektov, ki so shranjeni v njem. C zagotavlja tri različne načine dodelitve pomnilnika objektom:[43]
- statični: prostor za objekt je zagotovljen v dvojiški obliki med prevajanjem. Življenjska doba teh objektov je enaka času, ko je dvojiška datoteka, ki jih vsebuje, naložena v pomnilnik.
- avtomatični: začasni objekti se lahko shranijo na sklad, ta prostor pa se samodejno sprosti in je ponovno uporaben po tem ko se izstopi iz bloka v katerem so objekti označeni.
- dinamični: bloki pomnilnika poljubne velikosti se lahko zahtevajo med izvajanjem s pomočjo funkcij, kot sta
malloc
alicalloc
, iz dela pomnilnika, ki se imenuje kopica. Ti bloki obstajajo dokler se jih s klicanjem knjižničnih funkcijrealloc
alifree
ne sprosti za ponovno rabo.
Ti trije pristopi so primerni v različnih razmerah in imajo različne izkupnine. Statična dodelitev pomnilnika ima majhno dodelitveno povprečnino, avtomatična dodelitev jo lahko vsebuje nekaj več, dinamična dodelitev pomnilnika pa ima lahko precej večjo povprečnino tako za dodelitev kot za sprostitev. Trajna narava statičnih objektov je uporabna za ohranjanje stanja informacij med klici funkcij. Avtomatična dodelitev je preprosta za uporabo, vendar je običajno prostor sklada tipično bolj omejen in prehoden tako od statičnega pomnilnika ali od prostora kopice. Dinamična dodelitev pomnilnika omogoča priročno dodelitev objektov, katerih velikost je znana le med izvajanjem. Večina programov v C s pridom uporablja vse tri načine.
Kjer je možno, sta avtomatična in statična dodelitev najpreprostjši, ker pomnilnik upravlja prevajalnik, in programerju ni treba paziti na opravila, ki so potencialno dovzetna za napake ročnega dodeljevanja in sproščanja pomnilnika. Vendar se lahko veliko podatkovnih struktur med izvajanjem spreminja po velikosti, in, ker morajo imeti statične dodelitve (in avtomatične dodelitve pred standardom C99) fiksno velikost med prevajanjem, je velikokrat potrebna dinamična dodelitev.[43] Pred standardom C99 so bila polja s spreminjajočo velikostjo običajen primer tega. (Glej članek o funkciji malloc
za primer dinamično dodeljenih polj.) Z razliko od avtomatične dodelitve, ki lahko med izvajanjem odpove z nepredvidljivimi posledicami, funkcije dinamične dodelitve vračajo pokazatelj (v obliki vrednosti ničelnega kazalca) kadar zahtevan pomnilnik ne more biti dodeljen. (Statično dodelitev, ki je prevelika, po navadi zazna povezovalnik ali nalagalnik (loader), preden program sploh začne izvajanje.)
Dokler ni posebej označeno, statični objekti vsebujejo vrednosti nič ali ničelnih kazalcev pri izvajanju programa. Avtomatičnim in dinamičnim dodeljenim objektom se dodeli vrednost le, če je začetna vrednost eksplicitno označena, drugače imajo na začetku nedoločene vrednosti (tipično, katerikoli bitni vzorec, ki se nahaja v pomnilniku, in lahko predstavlja tudi nepravilno vrednost za določeni tip). Če program poskuša dostopati do nedodeljene vrednosti, so rezultati nedoločeni. Veliko sodobnih prevajalnikov poskuša zaznati in opozoriti na ta problem, vendar se lahko pojavijo tako napačno pozitivni kot napačno negativni.
Drug problem je, da mora biti dodelitev pomnilnika s kopico sinhronizirana s svojo dejansko rabo v kateremkoli programu da se lahko ponovno uporabi kolikokrat je mogoče. Če na primer vrednost edinega kazalca na pomnilniško dodelitev s kopico uide iz svojega področja ali se prepiše preko preden je klicana funkcija free()
, potem se tisti del pomnilnika ne more obnoviti za kasnejšo ponovno rabo in je dejansko za program izgubljen. Ta pojav je znan kot puščanje pomnilnika (memory leak). Možno je tudi obratno, da se pomnilnik sprosti, vendar se nanj še vedno sklicuje, kar lahko spet povzroči neprevidljive rezultate. Tipično se bodo simptomi pokazali v delu programa, ki je zelo oddaljen od dejanske napake, kar bo oteževalo sledenje problemu. Takšni problemi so izboljšani v jezikih s samodejnim čiščenjem pomnilnika.
Knjižnice
[uredi | uredi kodo]Osnovno razširitev jezika C predstavljajo knjižnice. Knjižnica je v C množica funkcij zbrana v eni »arhivski« datoteki. Vsaka knjižnica ima po navadi zaglavno datoteko s prototipi funkcij, ki jih vsebuje knjižnica in se lahko rabijo v programu, in označitvami posebnih podatkovnih tipov in makro simbolov znotraj teh funkcij. Da lahko program rabi knjižnico, mora vsebovati njeno zaglavno datoteko, knjižnica pa mora biti povezana s programom, kar v mnogih primerih zahteva prevajalnikove zastavice (na primer -lm
, okrajšano za »poveži z matematično knjižnico« (link the math library)).[43]
Najobičajnejša knjižnica C je standardna knjižnica jezika C, ki jo navajata standarda ISO in ANSI C. Standardna knjižnica je del vsake implementacije C. Implementacije, ki ciljajo na omejena okolja, kot so na primer vgradni sistemi, lahko zagotavljajo le podmnožico standardne knjižnice. Standardna knjižnica C podpira vhodno-izhodni tok, dodelitev pomnilnika, matematične funkcije in količine, znakovne nize in časovne vrednosti. Več ločenih standardnih zaglavnih datotek (na primer stdio.h
) določa vmesnike zanje in druge pripomočke standardne knjižnice.
Druge običajne množice funkcij knjižnice C so tiste, ki se rabijo v aplikacijah, posebej prirejenih za Unix in sisteme podobne Unix, še posebej funkcije, ki zagotavljajo vmesnik za jedro. Te funkcije v podrobnosti navajajo standardi, kot sta POSIX in Single UNIX Specification.
Ker je veliko programov napisanih v C, so na voljo raznolike druge knjižnice. Knjižnice so običajno napisane v C, ker C-jevski prevajalniki tvorijo učinkovito objektno kodo. Programerji nato naredijo vmesnike h knjižnici, tako da se lahko njeni podprogrami rabijo v visokonivojskih jezikih, kot so java, Perl in Python.[43]
Jezikovna orodja
[uredi | uredi kodo]Za pomoč programerjem v C pri iskanju in popravljanju stavkov z nedefiniranim obnašanjem ali z možnimi napačnimi izrazi so razvili več orodij z večjo strogostjo, ki jo zagotavljajo prevajalniki. Med prvimi takšnimi orodji je bilo orodje lint. Njegov razvoj je vodil do nastanka mnogih drugih.
Avtomatizirano preverjanje izvorne kode in preglejevanje je koristno v vsakem jeziku. Za C obstaja več takšnih orodij, kot na primer lint. Običajna praksa je, da se z orodjem lint odkrije vprašljiva koda, ko je program prvič napisan. Ko program preveri lint, se ga s prevajalnikom za C prevede. Poleg tega lahko mnogi prevejalniki opcijsko opozorijo o skladenjsko pravilnih konmstruktih, ki bodo verjetno dejansko napake. MISRA C je lastniška množica navodil v izogib takšni vprašljivi kodi, razvita za vgradne sisteme.[55]
Obstajajo tudi prevajalniki, knjižnice in mehanizmi na nivoju operacijskih sistemov za izvajanje procesov, ki niso standardni deli jezika C, kot na primer: preverjanje mej polj, odkrivanje prekoračitve medpomnilnika, serializacija, sledenje dinamičnemu pomnilniku in samodejno čiščenje pomnilnika.
Orodja, kot so pomnilniški razhroščevalniki: Purify, Valgrind, Insure++, dmalloc, Electric Fence, Inspector, libcwd, Memwatch, MTuner, Oracle Developer Studio, Splint, TotalView ali WinDbg skupaj s povezovanjem knjižnic, ki vsebujejo posebne različice funkcij dinamičnih dodelitev pomnilnika, lahko pomagajo odkrivati napake v rabi pomnilnika pri izvajanju.
Glej tudi
[uredi | uredi kodo]Opombe
[uredi | uredi kodo]- ↑ Izvedli so več poskusov, da bi bilo v C postopanje z znakovnimi nizi manj nagnjeno k napakam. Ena strategija je dodajanje varnejših in uporabnejših funkcij, kot sta
strdup
instrlcpy
, in izogibanje nevarnim funkcijam, kot je npr.gets
. Druga je dodajanje objektno usmerjene ovojnice okrog C-jevskih nizov, tako da so možna le varna klicanja. - ↑ Z razliko od C-ja imata npr. Fortran in BASIC omejeni model, ki ne vsebuje kazalcev. V paskalu so kazalci dinamični objekti, sam jezik pa ne dovoljuje kazalčne aritmetike.[11]
- ↑ Če se pozna programski jezik C, se pozna ukaz for. Ukaz for v jeziku Perl je skladenjsko enakovreden ukazu for v C-ju.
- ↑ Brez kazalcev bi C izgledal skoraj enako kot PHP.
- ↑ Standard ISO C (razdelek 5.1.2.2.1) zahteva veljavnost obeh oblik funkcije
main
, brez parametrov:int main()
oziroma:int main(void)
, ali z dvema parametroma:int main(int argc, char *argv[])
, kar je izjema le za to funkcijo. - ↑ Če se navede funkcija
main
samo s prvim parametrom:int main(int argc) { /* ... */ }
bo prevajalnik javil opozorilo, če pa se navede samo z drugim parametrom:
int main(char *argv[]) { /* ... */ }
bo javil napako, ker mora sicer funkcija
main
biti brez parametrov ali imeti strogo dva parametra, prvi parameter pa mora biti tipaint
. - ↑ V nekaterih operacijskih sistemih, še posebej v starejših različicah Unixa, ima lahko funkcija
main
tri parametre v obliki:int main(int argc, char *argv[], char *envp[]) { /* ... */ }
kjer je tretji parameter kazalec na vektor predvsem imen spremenljivk okolja. Tretji parameter
envp
v funkcijimain
pa ni v skladu s standardom POSIX in se podatki o obstoječih spremenljivkah okolja pridobivajo z drugimi funkcijami, na primergetenv
. Prevajalnikgcc
za Linux na primer to možnost podpira.
Sklici
[uredi | uredi kodo]- ↑ http://www.bell-labs.com/usr/dmr/www/chist.html
- ↑ http://cm.bell-labs.com/cm/cs/who/dmr/chist.html
- ↑ 3,0 3,1 »Verilog HDL (and C)« (PDF). The Research School of Computer Science at the Australian National University. 3. junij 2010. Pridobljeno 19. avgusta 2013.
1980s: ; Verilog prvič predstavljen ; na Verilog je vplival programski jezik C
- ↑ 4,0 4,1 Lawlis (1997).
- ↑ Stewart (2000a).
- ↑ 6,0 6,1 6,2 6,3 Ritchie (1993).
- ↑ Giannini; Code Fighter, Inc.; Univerza Columbia (2004), str. 164.
- ↑ 8,0 8,1 »WG14 N1570 Committee Draft — April 12, 2011« (PDF) (v angleščini). Pridobljeno 13. oktobra 2014.
- ↑ »Programming Language Popularity« (v angleščini). 2009. Pridobljeno 16. januarja 2009.
- ↑ »TIOBE Programming Community Index« (v angleščini). 2009. Arhivirano iz prvotnega spletišča dne 2. julija 2013. Pridobljeno 6. maja 2009.
- ↑ Johnson; Kernighan (1983), str. 52.
- ↑ »More Control Structures« (v angleščini).
- ↑ »Hands-On Ethical Hacking and Network Defense« (v angleščini).
- ↑ »C Language Tutorial« (v angleščini). Arhivirano iz prvotnega spletišča dne 13. septembra 2015.
- ↑ Stroustrup (1993).
- ↑ »Write Objective-C Code« (v angleščini). apple.com. 23. april 2013. Pridobljeno 22. decembra 2013.
- ↑ Dawkins (2006).
- ↑ Lee (2013).
- ↑ »How EiffelStudio Compiles«. docs.eiffel.com (v angleščini). Pridobljeno 2. februarja 2015.
- ↑ »Extending Python with C or C++«. docs.python.org (v angleščini). Pridobljeno 2. februarja 2015.
- ↑ 21,0 21,1 Stewart (2000b).
- ↑ Van der Linden (1994).
- ↑ Ritchie (1979).
- ↑ »History of C«. cppreference.com (v angleščini). 19. avgust 2014. Pridobljeno 10. novembra 2014.
- ↑ Stallings (2012), str. 91.
- ↑ »A Brief History of C« (v angleščini).
- ↑ Johnson; Ritchie (1978).
- ↑ 28,0 28,1 28,2 28,3 28,4 Kernighan; Ritchie (1988).
- ↑ Stroustrup (2002).
- ↑ »JTC1/SC22/WG14 – C«. Domača stran (v angleščini). ISO/IEC. Pridobljeno 2. junija 2011.
- ↑ Binstock (2011).
- ↑ »TR 18037: Embedded C« (PDF) (v angleščini). ISO / IEC. Pridobljeno 26. julija 2011.
- ↑ Harbison; Steele (2002).
- ↑ Kernighan; Ritchie (1978).
- ↑ Stran 3 izvirne K&R[34]
- ↑ 36,0 36,1 Kelley; Pohl (1984), str. 61.
- ↑ 37,0 37,1 »C Language Reference« (PDF). www.openwatcom.org (v angleščini). Arhivirano iz prvotnega spletišča (PDF) dne 13. maja 2011. Pridobljeno 31. decembra 2010.
- ↑ »10 Common Programming Mistakes in C++« (v angleščini). Cs.ucr.edu. Pridobljeno 26. junija 2009.
- ↑ Schultz (2004), str. 20.
- ↑ 40,0 40,1 »The form of a C program«. The GNU C Programming Tutorial (v angleščini). Pridobljeno 10. oktobra 2014.
- ↑ »WG14 N1256 Committee Draft — September 7, 2007: 5.1.2.2.1 Program startup« (PDF) (v angleščini). Pridobljeno 13. oktobra 2014.
- ↑ Larson (1996b).
- ↑ 43,0 43,1 43,2 43,3 43,4 43,5 43,6 Klemens (2014).
- ↑ Feuer; Gehani (1982).
- ↑ ISO/IEC 9899:1999 specification, TC3 (PDF) (v angleščini). str. 37, § 6.2.6.1 Representations of types — General.
- ↑ 46,0 46,1 46,2 46,3 ISO/IEC 9899:1999 specification, TC3 (PDF). str. 22, § 5.2.4.2.1 Sizes of integer types
<limits.h>
. - ↑ »64-Bit Programming Models: Why LP64?« (v angleščini). The Open Group. 1997. Pridobljeno 9. novembra 2011.
- ↑ ISO/IEC 9899, klavzula 6.7.5.1, odstavek 1.
- ↑ ISO/IEC 9899, klavzula 6.7.8, odstavek 10.
- ↑ ISO/IEC 9899, klavzula 7.17, odstavek 3: NULL..., ki se razširi na izvedbeno določeno kazalčno konstanto...
- ↑ gcc ima za ta namen na primer makro _FORTIFY_SOURCE. »Security Features: Compile Time Buffer Checks (FORTIFY_SOURCE)« (v angleščini). fedoraproject.org. Pridobljeno 5. avgusta 2012.
- ↑ Raymond (1996), str. 432.
- ↑ Summit (1995b), Question 6.23.
- ↑ Summit (1995b), Question 7.28.
- ↑ »Man Page for lint (freebsd Section 1)«. unix.com (v angleščini). 24. maj 2001. Pridobljeno 15. julija 2014.[mrtva povezava]
Viri
[uredi | uredi kodo]- Ashley, Michael (2004), »PHYS2020 - Computational Physics, based on the C programming language«, School of Physics, Univerza Novega Južnega Walesa (UNSW) (v angleščini), pridobljeno 8. oktobra 2014
- Banahan, Mike; Brady, Declan; Doran, Mark (1991), The C Book (2. izd.), Addison-Wesley
- Binstock, Andrew (12. oktober 2011), »Interview with Herb Sutter«, Dr. Dobb's (v angleščini), pridobljeno 7. septembra 2013
- British Standard Institute, The C Standard, John Wiley & Sons, ISBN 0-470-84573-2 Uradni standard ISO (C99) v knjižni obliki.
- Dawkins, Kyle (1. januar 2006), Examining Objective-C (v angleščini), pridobljeno 13. oktobra 2014,
Objective-C je objektno usmerjena stroga supermnožica C
- Dobravec, Tomaž (2010), abC (2. izd.), Ljubljana: Fakulteta za računalništvo in informatiko, COBISS 249744896, ISBN 978-961-6209-75-5
- Feuer, Alan R. (1998), The C Puzzle Book (1. izd.), Addison-Wesley, ISBN 978-0-201-60461-0
- Feuer, Alan R.; Gehani, Narain H. (Marec 1982), »Comparison of the Programming Languages C and Pascal«, ACM Computing Surveys, 14 (1): 73–92, doi:10.1145/356869.356872
- Giannini, Mario; Code Fighter, Inc.; Univerza Columbia (2004). »C/C++«. V Hossein, Bidgoli (ur.). The Internet encyclopedia. Zv. 1. John Wiley and Sons. ISBN 0-471-22201-1. Arhivirano iz prvotnega spletišča dne 13. decembra 2013. Pridobljeno 16. decembra 2012.
- Harbison, Samuel P.; Steele, Guy Lewis (1994), C: A Reference Manual (5. izd.), Englewood Cliffs, New Jersey: Prentice Hall, COBISS 1868566, ISBN 0-13-326224-3
- Harbison, Samuel P.; Steele, Guy Lewis (2002), C: A Reference Manual (5. izd.), Englewood Cliffs, New Jersey: Prentice Hall, COBISS 3299924, ISBN 0-13-089592-X Ta knjiga je odlična kot definitivni referenčni priročnik, ter za tiste, ki delajo na prevajalniku za C in procesorjih. Vsebuje skladnjo BNF za C.
- Jenko, Marjan (2014), Osnove programskega inženirstva, C (PDF), Ljubljana: Fakulteta za strojništvo, COBISS 276199168, ISBN 978-961-6536-80-6, arhivirano iz prvotnega spletišča (PDF) dne 16. novembra 2016, pridobljeno 16. novembra 2016
- Johnson, Stephen Curtis; Ritchie, Dennis M. (1978), »Portability of C Programs and the UNIX System« (PDF), Bell System Tech. J., 57 (6): 2021–2048, doi:10.1002/j.1538-7305.1978.tb02141.x, arhivirano iz prvotnega spletišča (PDF) dne 3. februarja 2015, pridobljeno 16. decembra 2012
- Johnson, Stephen Curtis; Kernighan, Brian Wilson (Avgust 1983), »The C language and Models for Systems Programming«, Byte, 8 (8): 48–60
- Jones, Derek M., The New C Standard: A Cultural and Economic Commentary (PDF), Addison-Wesley, ISBN 0-201-70917-1
- Juvan, Martin; Zaveršnik, Matjaž (2000), Vaje iz programiranja: C, C++ in Mathematica, Ljubljana: Študentska založba, COBISS 109207552, ISBN 961-6356-29-1
- Kelley, Al; Pohl, Ira (1984), A Book on C: Programming in C (4. izd.), Menlo Park, Kalifornija: Benjamin/Cummings Publishing Company, Inc., COBISS 871463, ISBN 0-201-18399-4
- Kernighan, Brian Wilson; Ritchie, Dennis (1978), The C Programming Language (1. izd.), Prentice Hall, ISBN 0-13-110163-3 Znana tudi kot K&R — izvirna knjiga o C-ju. Pred standardom ANSI C.
- Kernighan, Brian Wilson; Ritchie, Dennis (1988), The C Programming Language (2. izd.), Prentice Hall, ISBN 0-13-110362-8 ANSI C.
- King, Kim N. (april 2008), C Programming: A Modern Approach (2. izd.), W. W. Norton & Company, COBISS 1940037, ISBN 978-0-393-97950-3
{{citation}}
: Vzdrževanje CS1: samodejni prevod datuma (povezava) - Klemens, Ben (2014), 21st Century C (2. izd.), O'Reilly Media, ISBN 1-4919-0389-9
- Kochan, Stephen G. (2014), Programming in C, Upper Saddle River [etc.]: Addison-Wesley, COBISS 10745940, ISBN 0-321-77641-0
- Koenig, Andrew (1989), C Traps and Pitfalls, Reading, Mass.: Addison-Wesley, COBISS 2987248, ISBN 0-201-17928-8, OCLC 18014955
- Larson, Jim (13. september 1996), High and Low-Level C (v angleščini), arhivirano iz prvotnega spletišča dne 10. aprila 2015, pridobljeno 17. oktobra 2014
- Larson, Jim (31. december 1996), Standards and Style for Coding in ANSI C (v angleščini), arhivirano iz prvotnega spletišča dne 24. avgusta 2014, pridobljeno 29. oktobra 2014
- Lawlis, Patricia K. (Avgust 1997), »Guidelines for Choosing a Computer Language: Support for the Visionary Organization«, c.j. kemp systems, inc. (v angleščini), Ada Information Clearinghouse, arhivirano iz prvotnega spletišča dne 14. julija 2013, pridobljeno 18. julija 2006
- Lazić, Ranko (1991), Programski jezik C kroz primere (2. izd.), Beograd: Tehnička knjiga, COBISS 2088972, ISBN 86-325-0285-9
- Lee, Keith (2013), Pro Objective-C, Apres, ISBN 1-4302-5050-X
- Marshall, A. Dave (1999), »Programming in C, UNIX System Calls and Subroutines using C«, Univerza v Cardiffu (v angleščini), pridobljeno 17. oktobra 2014
- Oualline, Steve (1997), Practical C Programming (3. izd.), O'Reilly Media, COBISS 820587, ISBN 1-56592-306-5
- Pike, Rob (1989), Notes on Programming in C (v angleščini), pridobljeno 17. oktobra 2014
- Plauger, Phillip James; Brodie, Jim (1989), Standard C, Microsoft, COBISS 1958951, ISBN 1-55615-158-6
- Plauger, Phillip James (1991), The Standard C Library, Prentice Hall, COBISS 365693, ISBN 0-13-838012-0
- Prata, Stephen (2005), C primer plus (5. izd.), Indianapolis: Sams, COBISS 11265330, ISBN 0-672-32696-5
- Press, William Henry; Teukolsky, Saul Arno; Vetterling, William T.; Flannery, Brian P. (1992), Numerical Recipes in C: The Art of Scientific Computing (2. izd.), New York: Cambridge University Press, COBISS 3301927, ISBN 0-521-43108-5 (Razpoložljivo na spletu Arhivirano 2013-08-06 na Wayback Machine.)
- Raymond, Eric Steven (11. oktober 1996), The New Hacker's Dictionary (3. izd.), MIT Press, str. 432, ISBN 978-0-262-68092-9, pridobljeno 5. avgusta 2012
- Ritchie, Dennis (1974), »C Reference Manual« (PDF), Bellovi laboratoriji[mrtva povezava]
- Ritchie, Dennis (1979). The Evolution of the Unix Time-sharing System. Language Design and Programming Methodology conference. Arhivirano iz prvotnega spletišča dne 8. aprila 2015. Pridobljeno 25. oktobra 2014.
- Ritchie, Dennis (Marec 1993), »The Development of the C Language«, The second ACM SIGPLAN History of Programming Languages Conference (HOPL-II), ACM, 28 (3): 201–208, doi:10.1145/154766.155580, ISBN 0-89791-570-4, arhivirano iz prvotnega spletišča dne 23. maja 2013, pridobljeno 4. aprila 2005
- Sawtell, Chris (1994), C Lesson (v angleščini), arhivirano iz prvotnega spletišča dne 17. oktobra 2014, pridobljeno 17. oktobra 2014
- Scheffler, Thomas (2013), How to Think Like a Computer Scientist - 'C-Version', arhivirano iz prvotnega spletišča dne 25. maja 2015, pridobljeno 19. septembra 2015 Predelava knjige Downey, Allen B., How to Think Like a Computer Scientist - C++-Version
- Schildt, Herbert (1987), Artificial intelligence using C, Berkeley: Osborne/McGraw-Hill, COBISS 773, ISBN 0-07-881255-0
- Schildt, Herbert (1988), Advanced C (2. izd.), Berkeley: Osborne/McGraw-Hill, COBISS 17012736, ISBN 0-07-881348-4
- Schildt, Herbert (2000), C : The Complete Reference (4. izd.), Berkeley: Osborne/McGraw-Hill, COBISS 25067781, ISBN 0-07-212124-6
- Schreiner, Axel-Tobias (2011), Object oriented programming with ANSI-C (PDF), Hanser, str. 223, ISBN 3-446-17426-5
- Schultz, Thomas W. (2004), C and the 8051 (3. izd.), Otsego, MI: PageFree Publishing Inc., ISBN 1-58961-237-X, pridobljeno 10. februarja 2012
- Sedgewick, Robert (2009), Algorithms in C, Addison-Wesley, COBISS 23760935, ISBN 0-201-31452-5 (deli 1-4)
- Sedgewick, Robert (2009), Algorithms in C, Addison-Wesley, COBISS 23760679, ISBN 0-201-31663-3 (del 5)
- Stallings, William (2012), Operating Systems: Internals and Design Principles (7. izd.), Pearson Education, Inc., COBISS 15525910, ISBN 0-273-75150-6
- Stewart, William (7. januar 2000), »History of the C Programming Language«, Living Internet (v angleščini), pridobljeno 31. oktobra 2006
- Stewart, William (7. januar 2000), »Unix History«, Living Internet (v angleščini), pridobljeno 21. septembra 2015
- Stöcker, Horst (2006), Matematični priročnik z osnovami računalništva, Ljubljana: Tehniška založba Slovenije, COBISS 229576192, ISBN 86-365-0587-9
- Stoljarov, A. V. (2010), »Язык Си и начальное обучение программированию« (PDF), Sbornik statej molodih učjonih fakulteta VMK MGU, Izdatelskij otdel fakulteta VMK MGU (7): 78–90
- Stroustrup, Bjarne (1993), A History of C++: 1979−1991 (PDF) (v angleščini), pridobljeno 9. junija 2011
- Stroustrup, Bjarne (2002). Sibling rivalry: C and C++ (PDF) (poročilo). AT&T Labs.
- Summit, Steve (1995a), »C Programming Notes«, Univerza Washingtona (v angleščini), pridobljeno 17. oktobra 2014
- Summit, Steve (1995b), C Programming FAQs: Frequently Asked Questions, Addison-Wesley, COBISS 38837505, ISBN 0-201-84519-9
- Thompson, Kenneth, A New C Compiler (PDF), Murray Hill, New Jersey: AT&T Bellovi laboratoriji
- Van der Linden, Peter (1994), Expert C Programming: Deep C Secrets, Prentice Hall Professional, COBISS 7454041, ISBN 0-13-177429-8
- Vrabič, Rok; Kuščer, Lovro (2014), Osnove programskega jezika C (PDF), Ljubljana: Fakulteta za strojništvo, COBISS 13344283, arhivirano iz prvotnega spletišča (PDF) dne 9. novembra 2016, pridobljeno 5. maja 2016
- Vujičić, Vladan (1990), Uvod u C jezik (3. izd.), Vinča: Institut za nuklearne nauke" Boris Kidrič", COBISS 1652748, ISBN 86-80055-04-2
- Životić, Zoran (1990), »Moja škola C-a«, Računari, Mala PC biblioteka (65)
Zunanje povezave
[uredi | uredi kodo]- Stran o programskem jeziku C na eŠtudentu Arhivirano 2006-02-16 na Wayback Machine.
- http://www.educa.fmf.uni-lj.si/izodel/sola/2001/di/Rupar/izobrazevanje/tutorc/index.html
- Burden, Peter, Programming in C Arhivirano 2016-04-04 na Wayback Machine. (angleško)
- C na Dictionary of Programming Languages (angleško)
- Programming in C (zbirka dokumentov na Lysator) (angleško)
- Spletišče wiki IRC-kanala ##C na Freenode (angleško)
- Category/Library/C na FSF (angleško)
- ISO/IEC JTC1/SC22/WG14 - C (angleško)
- Free Online C / C++ Tutorials and Documentation (angleško)
- C reference na cppreference.com (angleško)
Spletni prevajalniki
[uredi | uredi kodo] url |
barvanje skladnje |
različni urejevalniki |
preverjanje prevoda |
izvajanje kode |
podprti jeziki |
izhod v zbirnem jeziku |
prevajalnik(i) |
opombe |
---|---|---|---|---|---|---|---|---|
codepad.org | Da | Da | Ne | Da | C, C++, ... | Ne | – | (angleško) |
comeaucomputing.com Arhivirano 2016-04-16 na Wayback Machine. | – | – | – | – | C, C++ | – | – | [mrtva povezava] |
compilr.com Arhivirano 2016-03-16 na Wayback Machine. | – | – | – | – | – | – | – | [mrtva povezava] |
delorie.com | – | – | – | – | – | – | – | [mrtva povezava] |
godbolt.org | Da | Ne | Da | Ne | C, C++ | Da | gcc, clang | (angleško) |
ideone.com | Da | Ne | Da | Da | C, C++ | Ne | gcc, clang | (angleško) |
melpon.org Arhivirano 2016-04-11 na Wayback Machine. | Da | 3× | Da | Da | C, C++, C#, ... | Ne | gcc, clang | (angleško) |
repl.it | Da | Ne | Da | Da | C, C++, C#, ... | Ne | gcc | (angleško) |
rextester.com | Da | 3× | Da | Da | C, C++, C#, ... | Ne | gcc, clang, vs C | (angleško) |
stacked-crooked.com | Da | Ne | Da | Da | C, C++ | Ne | gcc, g++ | (angleško) |