Programski jezik C je prvotno razvilDennis Ritchie med letoma 1969 in 1973 vAT&T Bellovih laboratorijih.[9][10][11] Ritchie inKen Thompson sta najprej razvilaprevajalnik 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. V 1980-ih je C postopoma pridobival na priljubljenosti. Postal je eden najbolj razširjenih programskih jezikov[12][13] s prevajalniki C, ki so na voljo za praktično vse sodobne računalniške arhitekture in operacijske sisteme.
Pred uradnim standardom za C se je mnogo uporabnikov in izvršiteljev opiralo na neuradno specifikacijo, opisano v knjigiProgramski jezik CBriana Wilsona Kernighana in Ritchieja.[14][15] Ta različica je v splošnem znana kot »K&R«C. Leta 1989 jeAmeriški državni inštitut za standarde (ANSI) objavil standard za C (v splošnem imenovan»ANSI C«ali »C89«). Naslednje leto sta to specifikacijo potrdiliMednarodna organizacija za standardizacijo (ISO) inMednarodna komisija za elektrotehniko (IEC) kot mednarodni standard (v splošnem imenovan »C90«). ISO in IEC sta kasneje izdali razširitev standarda za podporointernacionalizacije leta 1995 in popravljeni standard (znan kot»C99«) leta 1999. Ta standard je do sedaj najbolj razširjen. Trenutna različica standarda (sedaj imenovana»C23«) je ISO kot ISO/IEC 9899:2014 potrdila 31. oktobra 2024.[16]
C jeimperativniproceduralni jezik. Izdelan je bil za prevajanje na relativno preprostemprevajalniku in da bi zagotavljal nizkonivojski dostop dopomnilnika, jezikovne konstrukte, ki bi se učinkovito preslikali v tipične strojne ukaze in, da bi potreboval najmanjšopodporo izvajanja. Zaradi tega se je C začel rabiti v mnogih aplikacijah, ki so bile prej razvite z zbirnem jeziku, še posebej vsistemskem programiranju.
Navkljub svojim nizkonivojskim zmožnostim se je jezik C razvil v smislu boljšega programiranja namnogih platformah. Program zapisan v C, ki je v skladu s standardom in napisanprenosljivo, 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 vgrajenihmikrokrmilnikov do superračunalnikov.
C velja za učinkovit jezik in je primeren za sistemska opravila, ni pa najprimernejši za učenjeprogramiranja, čeprav se pogosto pojavlja vizobraževanju. Je tudieden od najbolj razširjenih programskih jezikov, skupaj zjavo,C++ aliPHP, od leta 2008 pa mu priljubljenost celo rahlo narašča.[12][13] Od leta 2000 se C stalno uvršča med prve štiri jezike vindeksu TIOBE, ki meri priljubljenost programskih jezikov.[17] Obstaja zelo maloarhitektur in operacijskih sistemov za katere ni na voljo prevajalnika za C. C se veliko rabi tudi za razvoj prenosljive uporabniške programske opreme.[6]
C je dokaj skop programski jezik, ki deluje blizustrojne opreme, in je za razliko od večine programskih jezikov bolj podobenzbirniku. 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 vsakemstroju. 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 imenujejonizkonivojski alisrednjenivojski jezik, kar označuje kako blizu strojne opreme lahko deluje.
V C-ju je vsaizvršna koda vsebovana znotrajpodprogramov, imenovanih »funkcije«, čeprav ne v strogem pomenufunkcionalnega programiranja.Parametri funkcij seprenašajo po vrednosti.Polja se prenašajo kotkazalci, to je kot naslov prvega elementa v polju.Prenos po sklicu se v C simulira z eksplicitnim prenašanjem vrednosti kazalcev na objekt, na katerega se sklicuje.
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:
veliko število aritmetičnih,bitnih, logičnih (enočlenih,dvočlenih,tročlenih) in pozapisnih operatorjev, kot so npr.:+,-,!,*,&,~,+=,++,||,<<,?:,.,-> ipd.,
v enem stavku se lahko izvede več kot enaprireditev,
funkcije:
vrnjene vrednosti funkcij se lahko prezrejo, kadar se ne rabijo
uporabniško definirani tipi (typedef) in sestavljeni tipi,
zapisi (records) ali skupki raznovrstnih podatkovnih tipov (struct), ki jih določi uporabnik, in omogočajo združevanje in upravljanje podobnihpodatkovnih elementov v celoti. Vsebine celih struktur ni mogoče primerjati z enim samim vgrajenim operatorjem (elemente je treba primerjati posamezno),
unija je struktura s prekrivajočimi se člani; omogoča, da več tipov podatkov deli isto pomnilniško lokacijo.
indeksiranjepolj je sekundarni zapis, opredeljen 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 tegaoglata oklepaja ([ ]) nakazujeta polja skladenjsko, na primermesec[11],
naštevni tipi (enumerated types) z rezervirano besedoenum. Niso opremljeni z označbami in so prosto medsebojno spremenljivi s celimi števili,
osnovna oblikamodularnosti: datoteke se lahko prevedejo samostojno inpovežejo skupaj, z nadzorom katere funkcije in podatkovni objekti so vidni v drugih datotekah prek atributovstatic aliextern,
označitvenaskladnja 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 njenihparametrov,
parametri, ki prehajajo vfunkcije po vrednosti in ne po sklicu (referenci),
ustvarjena koda ima po prevajanju razmeroma enostavne potrebe na osnovni platformi, zaradi česar je primerna za ustvarjanje operacijskih sistemov in za uporabo vvgrajenih sistemih.
Izvor jezika C je tesno povezan z razvojem operacijskega sistemaUnix, ki so ga izvirno razvili vzbirnem jeziku naminiračunalnikuDECPDP-7 Ritchie, Thompson,Joe Ossana, Rudd Canaday inDoug McIlroy v AT&T Bellovih laboratorijih, in vključili več zamisli svojih kolegov.[20] V začetku Thompson niti ni programiral na samem PDP-7, ampak je rabil množico makrojev za zbirni jezik GEMAP na32-bitnemosrednjem strojuGeneral ElectricGE-635. Nato je poprocesor tvoril papirni trak, ki ga je PDP-7 lahko prebiral.[10] Kmalu je Unix s preprostim jedrom, zbirnim jezikom, preprostolupino (tolmačem ukazov) in z nekaterimi pripomočki (kot npr. Unixovi ukazirm,cat,cp) leta 1969 postal samozadosten, in razvoj se je lahko nadaljeval neodvisno na samem PDP-7. McIlroy je kmalu zatem tvoril prvi visokonivojski jezik sistema Unix, izvedboprevajalnika prevajalnikovTMG Roberta M. McClurea. McIlroy inBob Morris sta uporabila TMG za zgodnji prevajalnik jezikaPL/I v operacijskem sistemuMultics. Thompson se je zaradi McIlroyjevega uspeha reproduciranja TMG odločil, da je Unix, ki verjetno tedaj še ni bil imenovan tako, potreboval lastensistemski programski jezik.
Pisanje v zbirnem jeziku novonastalega Unixa je bilo nerodno. Za pisanje programskih struktur se je porabilo več časa, kodo je bilo težje razhroščevati in jo razumeti.[21] 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 uporabitiFortran,[22] nato pa je ustvariljezik B s poenostavitvijo raziskovalnega sistemskega jezikaBCPL, ki ga je leta 1967 razvil Martin Richards, tako da je lahko njegovtolmač šel v 8kB18-bitnibesedni pomnilnik računalnika PDP-7. Uradni opis jezika BCPL tedaj ni bil na voljo.[23] Thompson je spremenil njegovo skladnjo z manjbesedami in podobno poenostavljenemuAlgolu, znanemu kot SMALGOL.[24] Jezik je imenovalB in ga opisal kot »semantika BCPL z veliko skladnje SMALGOL.«[10][24] Tako kot BCPL je imel Bzagonski prevajalnik za lažji prenos na nove stroje.[24] Vendar je bilo le nekaj pripomočkov na koncu napisanih v B, ker je bil prepočasen in ni mogel izkoristiti funkcij PDP-11, kot je na primerbajtno naslovljivost.
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 DECPDP-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.[20] Tudi njegov operacijski sistem je bil napisan v zbirnem jeziku.[10] Ž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.[19][24] Pomemben dodatek je bil znakovni podatkovni tip. Thompson je začel uporabljati NB za pisanjeUnixovega jedra in njegove zahteve so oblikovale smer razvoja jezika.[24][25] Do leta 1972 so bili jeziku NB dodani bogatejši tipi: NB je imelpolja tipovint inchar. Dodani so bili tudikazalci, zmožnost ustvarjanja kazalcev na druge tipe, polja vseh tipov in tipe, ki jih vračajo funkcije. Polja znotraj izrazov so postala kazalci. Napisan je bil nov prevajalnik in jezik se je leta 1972 preimenoval v C.[10] Postal je prevajalni in ne tolmačitveni jezik.
Prevajalnik C in nekateri pripomočki, izdelani z njim, so bili vključeni v različicoVersion 2 Unix, ki je znana tudi kotResearch Unix.[26]
Začetni razvoj jezika C je po Ritchiejevih besedah potekal v AT&T Bellovih laboratorijih med letoma 1969 in 1973.[10] Najbolj kreativno obdobje je bilo leta 1972. Tedaj je bila večina Unixa ponovno napisana v C-ju.[27] Do leta 1973 z dodatkom podatkovnega tipazapisovstruct je C postal dovolj močan za prevod Unixovegajedra. 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.[28] Novo jedro z reimplementacijo jezika C je imela različicaVersion 4 Unix, izdana novembra 1973.[10]
Predprocesor je bil predstavljen okoli leta 1973 na pozivAlana Snyderja in tudi kot priznanje uporabnosti mehanizmov za vključitev datotek, ki so na voljo v BCPL in PL/I. Njegova izvirna različica je vsebovala samo vključene datoteke in preproste zamenjave znakovnih nizov (stringov): makrov#include in#define brez parametrov. Kmalu za tem ga je razširil predvsemMike Lesk in nato John Reiser, da je vključeval makre z argumenti inpogojno prevajanje.[10]
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 sistemBurroughs B5000 (napisan vALGOLu) leta 1961. Leta 1977 sta Ritchie inStephen Curtis Johnson dodatno spremenila jezik C za pospešitevprenosljivosti operacijskega sistema Unix. JohnsonovPortable C Compiler (PCC) je služil kot osnova za več izvedb C-ja na novih platformah.[25]
Naslovnica izvirne prve izdaje knjigeProgramski jezik C (The C Programming Language) iz leta 1978
Leta 1978 sta Kernighan in Ritchie objavila prvo izdajo knjigeProgramski jezik C (The C Programming Language).[29] Ta knjiga, pri programerjih v C-ju znana kot »bela knjiga«(white book), oziroma »K&R«,[10] je bila mnogo let neformalnaspecifikacija jezika. Različica jezika C, ki ga knjiga opisuje, se navadno imenuje»K&R C«. Ker je bila izdana leta 1978, se včasih imenuje tudiC78.[30] Druga izdaja knjige[31] pokriva kasnejši standardANSI C, opisan spodaj.
sestavljeni prireditveni operatorji v obliki=op (kot npr.=-) so bili spremenjeni v oblikoop= (to je-=) 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 ANSI leta 1989, je K&R C še vedno mnogo let veljala za»najmanjši skupni imenovalec«na katerega so se programerji v C-ju omejili, kadar je bila zaž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 tipovint. Funkcije, ki so se rabile brez predhodnih označitev (deklaracij), so privzeto vračale vrednostiint, če so uporabile njihove vrednosti. Na primer:
longneka_funkcija();/* To je označitev funkcije, tako da *//* prevajalnik lahko pozna ime in tip *//* vrednosti, ki jo funkcija vrača *//* int */druga_funkcija();/* Druga označitev funkcije. Ker je *//* to zgodnja različica C, je tukaj *//* implicitni tip 'int'. Komentar kaže,*//* kje bi bil v kasnejših različicah *//* potreben izrecni določilnik tipa *//* 'int'. *//* int */klicna_funkcija()/* To je opredelitev funkcije, ki *//* vključuje njeno telo s kodo med *//* { zavitima oklepajema }. Ker ni *//* določen tip vračane vrednosti, *//* funkcija implicitno vrača tip 'int' *//* v tej zgodnji različici C. */{longtest1;register/* int */test2;/* Tukaj navedba tipa 'int' ni *//* potrebna. Določilnik tipa 'int' v *//* komentarju bi bil potreben v *//* kasnejših različicah C. Ključna *//* beseda 'register' nakazuje *//* prevajalniku, da se naj ta *//* spremenljivka idealno shrani v *//* register v nasprotju znotraj okvirja*//* sklada. */test1=neka_funkcija();if(test1>0){test2=0;}else{test2=druga_funkcija();}returntest2;}
Določilnike (specifikatorje) tipaint, 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, senjihovo preverjanje ni izvedlo, č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čenihorodij, kot na primer Unixov pripomočeklint, 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 posebejPCC[32]) in od nekaterih drugih ponudnikov. Med njimi so:
funkcije tipavoid (funkcije, ki ne vračajo vrednosti)
funkcije, ki vračajo podatkovne tipestruct aliunion (namestokazalcev. Pred tem so funkcije lahko vračale le en kazalec, celo številoint ali število s plavajočo vejicofloat)
naštevni tipi (enumerated types, pred tem so se rabile predporocesorske opredelitve za cele fiksne vrednosti, na primer#define dZELENA 3)
Veliko število razširitev, pomanjkanje dogovora ostandardni 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.[33]
Leta 1983 jeAmeriš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 predalidelovni skupini 1003IEEE, ki je postala osnova za standardPOSIX leta 1988. Leta 1989 so standard C potrdili kot ANSI X3.159-1989 »Programming Language C«. Ta različica jezika se po navadi imenujeANSI C, Standard C ali včasih C89.
Leta 1990 je standard ANSI C (z oblikovnimi spremembami) sprejelaMednarodna organizacija za standardizacijo (ISO) kot ISO/IEC 9899:1990, kar se včasih imenuje C90. Tako se izraza »C89«in »C90«nanašata na isto različico programskega jezika.
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 skupinaISO/IEC JTC1/SC22/WG14. Nacionalna usvojitev posodobitve mednarodnega standarda se po navadi izvede še v letu publikacije ISO.
Eden od ciljev procesa standardizacije jezika C je bilo tvorjenjesupermnož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++), kazalcivoid, podpora za mednarodninabor znakov inlokalnih parametrov, ter predprocesorske izboljšave. Čeprav je bilaskladnja 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 odvisnestrojne opreme, se bo izvajal pravilno na katerikoliplatformi 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žnicegrafičnih uporabniških vmesnikov (GUI), ali oslonitev na računalniške ali specifične platformske atribute, kot je točna velikost podatkovnih tipov inureditev bajtov (endianost,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.[34]
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.[35]
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č tipaint. Standardni makro__STDC_VERSION__ je določen z vrednostjo199901L 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 vMicrosoft Visual C++ izpolnjuje standard C89 in tiste dele C99, ki so zahtevani za združljivost z različico standardaC++11.[37]
Poleg tega standard C99 zahteva podporo zaoznačevalnike (identifikatorje)Unicode v oblikiubežnih znakov (escape characters) (na primer\u0040 ali\U0001f431) in predlaga podporo za surova imena Unicode.
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 C 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 podporakodirnega standardaUnicode, 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++. Standardnimakro__STDC_VERSION__ je opredeljen kot201112L in tako označuje, da je na voljo podpora standardu C11.
C17 je neuradno ime za standard programskega jezika C, objavljen junija 2018 kot ISO/IEC 9899:2018. Ne uvaja novih jezikovnih gradnikov, le tehnične popravke in pojasnila za napake v C11. Standardni makro__STDC_VERSION__ je opredeljen kot201710L in tako označuje podporo standardu C17.
C23 je neformalno ime za trenutno večjo standardno različico jezika C. Med celotnim razvojem je bila neuradno znana kot »C2X«. C23 je bila objavljena 31. oktobra 2024 kot ISO/IEC 9899:2024.[16] Standardni makro__STDC_VERSION__ je opredeljen kot202311L in tako označuje podporo standardu C23.
C2Y je neuradno ime za naslednjo večjo standardno različico jezika C po C23 (C2X), ki bo verjetno objavljena v kasnejših 2020-ih. Zato nosi ime '2' in »C2Y«. Delovna skupinaISO/IEC JTC1/SC22/WG14 je 21. februarja 2024 objavila zgodnji delovni osnutek kot N3220.[38]
Leta 2008 jestandardizacijski pododbor SC 22 objaviltehniško poročilo z razširitvijo jezika C,[39] ki se je nanašala na probleme med razširitvami jezika C za različnevgradne 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 vhodnoizhodno naslavljanje strojne opreme.
Vgradni C rabi večino skladnje in semantike standardnega C-ja: funkcijamain, 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.
C imaformalno slovnico, ki jo določa standard C.[40] Z razliko od nekaterih drugih jezikov, kot je npr.FORTRAN 77, je izvorna koda C-ja proste oblike, kjer seznaki za prazni prostor lahko rabijo poljubno, koda pa ni odvisna od stolpčnih ali besedilno-vrstičnih omejitev. Konci vrstic v C na splošno niso pomembni, meje vrstic pa so drugače med predprocesorsko fazo pomembne.
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 znotrajznakovnega niza ali znakovnegačrkovnega simbola, se ne obravnavata kot razmejilna znaka komentarja.[31]:192 Komentarji oblike:
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.
Datoteke s C-jevsko izvorno kodo vsebujejo označitev (deklaracijo) in opredelitev (definicijo) funkcij. Opredelitve funkcij po vrsti vsebujejo označitve instavke. Označitve opredeljujejo nove podatkovne tipe z rezerviranimi besedami, kot so:struct,union inenum, ali prirejajo tipe in morda rezervirajo pomnilniška mesta novim spremenljivkam, po navadi z zapisom tipa, ki mu sledi ime spremenljivke. Rezervirane besede, kot stachar inint, označujejo vgrajene tipe. Deli kode so obdani zzavitima oklepajema{ in}, ki omejujeta označitvenidoseg ali pa delujeta kot samostojni stavek zanadzorne strukture.
C kot imperativni jezik za označitev dejanj rabistavke. Najbolj razširjeni stavek jeizrazni stavek, ki vsebuje izraz, kateremu je treba določiti vrednost, izrazu pa sledipodpičje. Zaradi še večje preglednosti se podpičje velikokrat razmakne od označitvenih/ukaznih besed z dodatnim presledkom. Na primer:
inta;|inta;for(i=0;i<max;i++)|for(i=0;i<max;i++)
Kotstranski pojav določitve vrednosti se funkcije lahkokličejo in spremenljivkam se lahkopriredijo nove vrednosti. Za spreminjanje normalne zaporedne izvršitve stavkov ima C več stavkov za nadzor pretoka, ki jih označujejo rezervirane besede.Strukturalno programiranje je podprto s pogojno izvršitvijoif ... [else], z iterativnimi izvršitvami (zankami)do ...while,while infor. Stavekfor ima ločene dodelitvene izraze, izraze za preverjanje in izraze za ponovno dodelitev– vsak od njih pa se lahko opusti. Izrazabreak incontinue se lahko rabita v zankah.break se rabi za zapustitev najbolj notranjega zančnega stavka,continue pa za preskočitev na njeno ponovno dodelitev (alokacijo). Obstaja tudi nestrukturalni stavekgoto, ki preusmerja neposredno na imenovanooznako (label) znotraj funkcije. Oznake so tvorijo z imeni, ki jim sledidvopičje– na primeroznaka:.switch izbere primercase, ki se izvede na podlagi vrednosti celoštevilskega izraza. Za razliko od mnogih drugih jezikov bo nadzorni pretok padel v naslednji primercase, razen če ga prekine prekinitevbreak.
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 pojavi (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 (&&,||,?: inoperator 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 knjigeProgramski 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.«[29]:3 Standard C ni poskušal popraviti veliko od teh hib zaradi vpliva takšnih sprememb na že obstoječo programsko opremo.
Nova vrstica označuje konec besedilne vrstice. 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 prikazuliteralov znakovnih nizov, vendar niso povsemprenosljivi. Od standarda C99 se lahko prenosljivo vgradijo mnogonacionalni znaki kodirnega standardaUnicode v besedilo izvorne kode C s pomočjo kodiranj\uXXXX ali\UXXXXXXXX, kjerX označuješestnajstiško zapisan znak.
Osnovni izvršni nabor znakov C obsega enake znake, skupaj s prikazomopozorila (alert),povratnega znaka (backspace) inpomika na začetek vrstice (carriage return). Podporaizvajalnemu času (runtime) za razširjene nabore znakov se je z vsako različico standarda za C povečevala.
Besede soobčutljive na male ali velike črke.INT,INt,InT,Int,iNT,iNt aliinT na primer ni enako kotint. 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 dvemapodčrtajema, npr.__asm,_Cdecl ipd.[43] V primerjavi z drugimi velikimi jeziki je imel 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 posebnimisimboli in rezerviranimi besedami.[41]
C99 je dodal pet rezerviranih besed (‡ označuje drugačen črkovalni vzdevek za rezervirano besedo C23):
C11 je dodal še sedem razerviranih besed (‡ označuje drugačen črkovalni vzdevek za rezervirano besedo C23):
_Alignas ‡
_Alignof ‡
_Atomic
_Generic
_Noreturn
_Static_assert ‡
_Thread_local ‡
C23 je dodal še 15 rezerviranih besed:
alignas
alignof
bool
constexpr
false
nullptr
static_assert
thread_local
true
typeof
typeof_unqual
_BitInt
_Decimal32
_Decimal64
_Decimal128
Večina nedavno rezerviranih besed se začne s podčrtajem, ki mu sledi velika začetnica, ker so bili označevalniki te oblike predhodno rezervirani s standardom C za uporabo samo v izvedbah. Ker obstoječa izvorna koda programa ne bi smela uporabljati teh označevalnikov, na to ne bi vplivalo, ko bi izvedbe C začele podpirati te razširitve programskega jezika. Nekatere standardne zaglavne datoteke opredeljujejo bolj priročne sinonime za podčrtane označevalnike. Nekatere od teh besed so bile dodane kot rezervirane besede z običajnim črkovanjem v C23, ustrezni makri pa so bili odstranjeni.
Na začetku je imel C manj rezerviranih besed, na primer 29, sedaj pa jih pozna 63. Besedaentry se je redko ali pa nikoli rabila in sedaj ni več rezervirana. V drugi izdaji knjigeProgramski jezik C sta Kernighan in Richie zapisala:»... [rezervirana beseda]entry, prej rezervirana, a nikoli uporabljena, ni več rezervirana.«in: »Mrtvorojena rezervirana besedaentry je umaknjena.«[31]:192, 259
C podpira bogat naboroperatorjev, ki so simboli znotrajizraza za določevanje potrebnih opravil med njegovim izvajanjem. Njegovi operatorji so razdeljeni na osemnajst kategorij. C ima operatorje za:
C rabi operator=, ki je v matematiki rezerviran za izražanjeenakosti, za naznanitev prireditve po zgledu predhodnih jezikovFortrana inPL/I, vendar z razliko odALGOLa 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 izrazif (a == b + 1) se na primer lahko napačno zapiše kotif (a = b + 1) in bo njegova vrednost po izvršitvi pravilna (true), če jea enak0 po prireditvi.[44]
Operatorska prednost v C ni vedno intuitivna, saj se na primer operator== zvezuje tesneje (se izvrši pred) kot operatorja& (bitni IN (AND) in| (bitni ALI (OR) v izrazih, kot jex & 1 == 0, ki bi moral biti zapisan kot(x & 1) == 0, če je bil to namen programerja.[45]
Osnovni gradnik programa v C je funkcija.[46] 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}).
Izvirni programPozdravljen, svet (»Hello, World!«) se je pojavil v prvi izdaji knjigeProgramski jezik C in je postal model za uvodni program v večini učbenikov programskih jezikov:[29]:6
main(){printf("hello, world\n");}
Spodnji zgled izpiše znakovni niz »Pozdravljen, svet!«nastandardni izhod s funkcijoprintf. Navadno je standardni izhod povezan s terminalom ali z zaslonom monitorja, lahko pa je tudi datoteka ali kakšna druga strojna naprava. Program je napisan v skladu s standardomANSI C.[d]
Prva vrstica v programu jepredprocesorski ukaz (navodilo, direktiva)#include. Pred samim prevajanjem programa predprocesor pregleda izvorno kodo in izvrši vse predprocesorske ukaze. Ti ukazi se vedno začnejo zznakom#. Ukaz#include povzroči, da se na njegovo mesto v izvorno kodo vključi datotekastdio.h, ki vsebuje standardne vhodnoizhodne funkcije.
intmain(void)
V naslednji vrstici se opredeli funkcija z imenommain. Ta funkcija ima poseben pomen v C programih. Pri začetkuizvajanja programa se najprej kliče ta funkcija. Rezervirana besedaint na začetku vrstice pove, da funkcijamain izvajalnemu sistemu vrne celo število, rezervirana besedavoid pa, da funkcija ne sprejme nobenih parametrov. Funkcijamain po standarduANSI 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. Funkcijamain je lahko opredeljena s pomočjo naslednjih štirih oblik ob označitvi:[47][e][f][g][h]
Prvi dve opredelitvi sta enakovredni (in združljivi s C++).
{
Odprti zaviti oklepaj pomeni začetek opredelitve funkcijemain.
printf("Pozdravljen, svet!\r\n");
V tej vrstici se kliče funkcijaprintf, ki je označena v datotekistdio.h. Pri tem klicu se funkcijiprintf poda en parameter v obliki znakovnega niza, ki jepomnilniški naslov prvega znaka vliteralu znakovnega niza"Pozdravljen, svet\r\n". Literal znakovnega niza je neimenovanopolje, ki jo samodejno nastavi prevajalnik, z elementi tipachar in končnimznakom NULL (vrednost ASCII 0), ki označuje konec polja, kar omogoča funkcijiprintf, da določi dolžino niza). Znak NULL se lahko zapiše tudi kotubežno zaporedje\0. Dvoznakovni niz\n je standardno ubežno zaporedje, ki se v C prevede v znaknove vrstice (EOL,end of line). Znak je namenjen kot ukaz izhodni napravi, da postavi trenutno lego na začetek naslednje vrstice. Vrnjena vrednost funkcijeprintf je tipaint, vendar je tiho zavržena, ker se ne uporablja. Previdnejši program lahko preizkusi vrnjeno vrednost, da preveri, ali je funkcijaprintf uspela.Podpičje; prekine stavek.
return0;
Vrstica zaključi izvajanje funkcijemain in vrne celo število0.
}
Zaprti zaviti oklepaj pomeni zaključek opredelitve funkcijemain. Po specifikaciji standarda C99 in novejših bo funkcijamain (za razliko od vseh drugih funkcij) implicitno vrnila vrednost0 preden doseže}, ki prekine funkcijo.[i] Vrnjeno vrednost0 izvajalni sistem tolmači kot izhodno kodo, ki označuje uspešno izvedbo funkcijemain.[48]
Katera opredelitev funkcijemain se uporabi v programu, je verjetno odvisno od posamezne izbire. Trenutni standard C vsebuje dva zgleda rabemain() in dvamain(void), standard C++ pa rabimain(). Vrednost, ki jomain vrača (in mora biti tipaint), služi kotstatus prekinitve. Tega program vrne gostiteljevemu okolju.
Standard C opredeljuje vrnitveni vrednosti0 (»nič napak«(zero errors)) inEXIT_SUCCESS, ki označujeta uspeh, terEXIT_FAILURE za označevanje neuspešnega izvajanja programa. (EXIT_SUCCESS inEXIT_FAILURE sta opredeljeni v standardni zaglavni datotekistdlib.h). Druge vrnitvene vrednosti služijo kot izvedbeni opredelitveni pomeni. VLinuxu na primer program, ki ga je prekinil ukazsignal, vrne kodo številske vrednosti signala plus 128.
Najmanjši pravilen program v C vsebuje prazno funkcijomain brez parametrov:
intmain(void){}
Lahko se zapiše tudi v več vrsticah:
intmain(void){/* začetek telesa funkcije v prvem */}/* stolpcu vrstice */
ali redkeje sicer v skladu z dobrim slogom:
int/* podatkovni tip vrnjene vrednosti */main(void)/* funkcije. Ime funkcije v prvem */{/* stolpcu vrstice. Začetek telesa */}/* funkcije v prvem stolpcu vrstice */
Sploh pa je slaba praksa pisati neporavnano, kot npr:
intmain/* *** * * **/(void){}
ali:
intmain/* ** * * ***/(void){}
oziroma poravnano brez reda:
intmain/*** * ****/(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.
Okroglaoklepaja (), 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 nemain (void), z razliko odsizeof (), ki dejansko strogo ni funkcija, in je skladenjska rezervirana beseda zaenočlenioperator.[49]sizeof je lahko podobno kotreturn brez okroglih oklepajev. Prireturn je to celo zaželeno, razen če je dvoumno.
Ker nista navedenareturn aliexit, funkcijamain ob izhodu vrne0.[48] To je poseben primer predstavljen v standarduC99, ki velja le za funkcijomain. Če se zahteva še ta navedba, ima najmanjši program obliko:
intmain(void){return0;}
Funkcijamain 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 funkcijamain.[46] Funkcijemain ni možno klicati ali jo zagnati s kakšno drugo funkcijo v programu. Kliče jo lahko leoperacijski sistem in na ta način se zažene program v C. Funkcijamain ni nikoli statična, in, če je navedena kotstatic 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 imenujejoprostostoječe (free-standing). V prostostoječi izvedbi ni podrobnega opisa kako naj obravnava izvajanje programa. V programu še posebej ni treba opredeliti funkcijemain.
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čitvijozaglavnih datotek spredprocesorskim ukazom#include, objekti knjižnice pa se povežejo v končno izvršno sliko. Določene knjižniške funkcije, kot sta na primerprintf aliscanf, so opredeljene s standardom C, in se imenujejostandardne knjižniške funkcije.
Funkcija lahko vrne vrednost klicatelju– po navadi drugi funkciji C-ja, ali gostiteljevemu okolju za funkcijomain. Zgoraj omenjena funkcijaprintf vrne koliko znakov je bilo izpisano, vendar se ta vrednost običajno prezre.
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čjotipske opustitve (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 posebejkazalci na funkcije. (Ritchiejeva zamisel je bila, da se določilniki označijo v kontekstu njihove rabe:»označitev zrcali rabo.«)[31]:122
C-jevskeobič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 enake širine na primer zahteva pretvorbo predznačene vrednosti v nepredznačeno. To lahko povzroči nepričakovane rezultate, če je predznačena vrednost negativna.
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 indouble), ter štirih izbirnih določilnikov (signed,unsigned,short inlong). Vsi razpoložljivi osnovni aritmetični tipi so navedeni v razpredelnici:
najmanjša naslovljiva enota stroja, ki lahko vsebuje osnovni nabor znakov. Njen tip jeceloštevilski. Dejanski tip je lahko predznačen ali nepredznačen, kar je odvisno od izvedbe. VsebujeCHAR_BIT bitov in njegov obseg je [−128,+127].[51]
8
CHAR_MIN / CHAR_MAX
%c
—
signedchar
enaka velikost kotchar, vendar je zagotovo predznačena in njegov obseg je [−128,+127].[51][j]
8
SCHAR_MIN / SCHAR_MAX
%c(ali%hhi za numerični vnos)
—
unsignedchar
enaka velikost kotchar, vendar je zagotovo nepredznačena. V dvojiškem zapisu je predstavljen brez zapolnjevalnih bitov, tako je njegov obseg točno [0,2CHAR_BIT−1],[52] običajno [0,+255][53]
8
0 / UCHAR_MAX
%c(ali%hhu za numerični vnos)
—
short shortint signedshort signedshortint
predznačeni celoštevilski tipshort. Njegov obseg je vsaj [−32.768,+32.767].[54][51][j]
predznačeni celoštevilski tiplong long. Njegov obseg je vsaj [−9.223.372.036.854.775.808,+9.223.372.036.854.775.807].[54][51][j] Uveden s standardomC99.
tip za realna števila s plavajočo vejico in dvojno točnostjo. Dejanske značinosti niso navedene (razen spodnjih mej), vendar je na večini sistemov todvojiški format števila s plavajočo vejico in dvojno točnostjo IEEE 754 (64 bitov). Ta format zahteva izbirni Annex F »IEC 60559 floating-point arithmetic.«
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, dalong long ni manjši odlong, ki ni manjši odint, ta pa ne manjši odshort. Ker je velikostchar vedno najmanjši podprti podatkovni tip, vsi drugi podatkovni tipi ne morejo biti manjši.
Najmanjša velikost zachar je8 bitov, najmanjši velikosti zashort inint sta 16 bitov, zalong 32 bitov in zalong long mora vsebovati vsaj 64 bitov.
Tipint 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 opredeljuje kako različni programi med seboj komunicirajo, enotni podatkovni model se rabi znotraj uporabniškega vmesnika danega operacijskega sistema.[56]
Treba je omeniti, da je v praksi velikost tipachar po navadi 8 bitov, tipashort pa 16 bitov (kakor tudi njihova nepredznačena dvojnika). To velja za platforme pogoste v 1990-ih, kot so:SunOS 4 Unix, MicrosoftMS-DOS, sodobniLinux in Microchip MCC18 za vgradne 8-bitne mikrokontrolerje PIC.POSIX zahteva, da je velikostchar točno 8 bitov.
Tudi dejanska velikost in obnašanje tipov s plavajočo vejico se razlikuje v izvedbah. Edino zagotovilo je, dalong double ni manjši oddouble, ki ni manjši odfloat. Če ju strojna oprema podpira, se po navadi rabita 32-bitna in 64-bitna dvojiška formata s plavajočo vejicoIEEE 754.
C podpira rabokazalcev, vrstosklica, 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 lahkodereferencirajo 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 alikazalč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:[57][n]
podatkovni_tip*ime_kazalca;
Na primer:
int*ptr;
To označiptr kot označevalnik objekta naslednjega tipa:
kazalec, ki kaže na objekt tipaint
To se običajno navede bolj zgoščeno kot 'ptr je kazalec naint'. 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:[n]
int*ptr;int*ptr;int*ptr;
Običajno se rabi zapis operatorja posrednosti brez presledka (desnostično) pred imenom kazalcaint *ptr;, predvsem zaradi nedvomljivosti pri hkratnih večkratnih opredelitvah:
int*ptr1,*ptr2,a,b;
int*ptr1,ptr2,a,b;
V zadnjem zapisu je kazalec samo spremenljivkaptr1.
Ker C ne opredeljuje implicitne dodelitve za objekte s samodejnim pomnilniškim trajanjem,[58] je treba biti velikokrat previden pri zagotavljanju, da je naslov, na katerega kažeptr, veljaven. Zaradi tega včasih predlagajo, da se kazalcu eksplicitno dodeli vrednostničelnega kazalca (null pointer value), ki je v C tradicionalno določena s standardiziranim makrojemNULL:[59]
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 funkcijiprintf 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časegmentacijsko odpoved (segmentation fault) ali popolnosesutje programa:[60]:33
int*ptr=NULL;*ptr=42;/* dereferenciranje vrednosti ničelnega *//* kazalca je nedoločeno */
Vrednosti ničelnih kazalcev so uporabne pri nakazovanju posebnih primerov, kot so brez »naslednjega«kazalca v končnem vozliščupovezanega seznama, ali kot naznanitev napake iz funkcij, ki vračajo kazalce. V ustreznih kontekstih izvorne kode, kot je prirejanje kazalčne spremenljivke, se lahkokonstanta ničelnega kazalca zapiše kot0, z ali brez eksplicitne opustitve na tip kazalca, ali kot makroNULL, ki je opredeljen v več standardnih zaglavnih datotekah, ali od standarda C23 naprej kot konstantanullptr. V pogojnih zvezah imajo vrednosti ničelnih kazalcev napačno vrednost (false), vse druge vrednosti kazalcev pa pravilno (true).
Kazalci se v C rabijo za več namenov. Z besedilnimiznakovnimi nizi se običajno upravlja s pomočjo kazalcev v polja znakov.Dinamična dodelitev pomnilnika se izvaja s kazalci. Rezultat funkcijemalloc je običajno pretvorjen v podatkovni tip podatkov, ki jih je treba shraniti. Mnogo podatkovnih tipov, kot so na primer povezani seznami alidrevesa, je velikokrat izvedeno kot dinamično dodeljeni objektistruct, ki so med seboj povezani s kazalci. Kazalci na druge kazalce se pogosto uporabljajo v večrazsežnostnih poljih in poljih strukturnih objektov.
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. Enostavno jih je tudi pretvoriti v in iz poljubnega tipa objektnega kazalca. V mnogih zvezah se jih dejansko implicitno pretvori.[48]
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) (dangling pointers)– lahko se uporabijo brez, da bi se jim dodelila vrednost (divji kazalci (wild pointers)), 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.
Podatkovni tipipolj imajo v C tradicionalno fiksno, statično velikost med prevajanjem. Standard C99 dovoljuje tudi oblikopolj s spremenljivo dolžino. Možno je tudi dodeliti blok pomnilnika (poljubne velikosti) pri izvajanju s pomočjo standardne knjižniške funkcijemalloc (calloc) 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čnone preverjajo za vezano velikost polja, čeprav nekateri prevajalniki lahko preskrbijopreverjanje mej kot možnost.[61][62] 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,prekoračitve 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čevanjeureditve po vrsticah. Mnogorazsežna polja se velikokrat rabijo v numeričnih algoritmih, večinoma iz uporabnelinearne algebra za hranjenje podatkovmatrik. Zgradba cejevskega polja je za to posebno nalogo zelo primerna. Ker se polja večinoma prenašajo kot kazalci, morajo biti, sploh v zgodnjih različicah jezika C, njihove meje fiksne vrednosti ali pa jih je treba izrecno prenesti 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.
Poljepolje se na primer lahko označi in uporabi na naslednje načine:
intpolje[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 dolžino«(variable-length array, VLA), ki rešujejo nekatere, vendar ne vse, probleme običajnih cejevskih polj. Naslednji zgled z uporabo sodobnega jezika C (C99 ali novejši) prikazuje dodelitev dvorazsežnega polja nakopico s pomočjo funkcijemalloc in uporabo večrazsežnega indeksiranja polja za dostope (ki lahko uporablja preverjanje meja na mnogih prevajalnikih C):
In tukaj je podobna izvedba z uporabo gradnika samodejnega VLA standarda C99:[o]
intfunc(intN,intM){/* Pozor: preveriti je treba, da *//* N * M * sizeof(float) NE presega *//* omejitev za samodejne VLA in je *//* znotraj razpoložljive velikosti *//* sklada. */floatp[N][M];/* Samodejni VLA se hrani na skladu in *//* se spremeni v velikost, ko je */for(inti=0;i<N;i++){/* funkcija priklicana */for(intj=0;j<M;j++){p[i][j]=i+j;}}print_array(N,M,p);/* ni potrebe za funkcijo free(p), saj *//* bo objekt pri izhodu iz funkcije *//* func() izginil, vključno s */return1;/* preostankom okvirja sklada */}
Zapis s spuščenimi indeksix[i] (kjerx označuje kazalec) jeskladenjski sladkor za*(x+i).[63] S prednostjo pomnilnikovega znanja o kazalčnem tipu naslov, na katerega kažex + i, ni osnovni naslov (na katerega kažex), povečan zai bitov, ampak je določen kot osnovni naslov, povečan zi pomnoženim z velikostjo elementa, na katerega kažex. Takox[i] označujei+1-ti element polja.
V večini izraznih kontekstov, kjer je večja izjema operandsizeof, se naprej izraz tipa 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 semantikoklicev po vrednosti, so tako polja učinkovito prenesena po sklicu.
Skupna velikost poljax se lahko določi s pomočjo operatorjasizeof na izraz tipa polja. Velikost elementa se lahko določi z operatorjemsizeof na poljubni dereferenciran elementx, kot v izrazun = sizeof *x alin = sizeof x[0], tako, da se število elementov v označenem poljux lahko določi kotsizeof x / sizeof x[0]. Zadnji izraz velja le za imena polj: spremenljivke označene s spuščenimi indeksi (int x[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 jesizeof vptr / sizeof vptr[0] (kjervptr označuje kazalec), ne bodo delovali, saj prevajalnik privzame, da se zahteva velikost kazalca samega.[64][65] Ker parametri imena polja nasizeof 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 operatorjemsizeof 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;staticconstintvelikost=10;vptr=(int*)malloc(velikost*sizeof(vptr));funkcija(vptr,velikost);free(vptr);/* ... */}funkcija(int*v,intn)/* 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 nil-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 funkcijememcpy ali z dostopanjem do posameznih elementov.
Strukturastruct je označitevsestavljenega podatkovnega tipa (alizapisa), ki opredeljuje fizično združen seznam spremenljivk pod enim imenom v bloku pomnilnika, kar omogoča dostop do različnih spremenljivk prek enega samega kazalca ali z označenim imenomstrukture, ki vrne isti naslov. Podatkovni tipstruct lahko vsebuje druge podatkovne tipe, zato se uporablja za zapise mešanega tipa podatkov, kot je vnos imenika trdega diska (dolžina datoteke, ime, pripona, fizični naslov itd.) ali druge zapise mešanega tipa (ime , naslov, telefon, stanje itd.).
Struktura se neposredno sklicuje na sosednji blok fizičnega pomnilnika, ki je običajno razmejen (po velikosti) z mejami dolžine besede. Ustreza funkciji s podobnim imenom, ki je na voljo v nekaterihzbirnikih za procesorje Intel. Ker je vsako polje v strukturi blok neprekinjenega pomnilnika, se od začetka nahaja na določenem fiksnem odmiku.
Ker je vsebina strukture shranjena v neprekinjenem pomnilniku, je treba za pridobitev števila bajtov, potrebnih za shranjevanje določene vrste strukture, uporabiti operatorsizeof, tako kot se lahko uporablja zaprimitive. Poravnava določenih polj v strukturi (glede na mejebesed) je specifična za izvedbo in lahko vključuje oblazinjenje, čeprav sodobni prevajalniki običajno podpirajo ukaz#pragma pack, ki spremeni velikost v bajtih, uporabljenih za poravnavo.[66]
V jezikuC++ je struktura enakarazredu C++, vendar ima drugačno privzeto vidnost: člani razreda so privzeto zasebni, medtem ko so člani strukture privzeto javni.
V C in C++ so neoznačeneunijeunion izražene skoraj tako kot strukture (struct), le da se vsak podatkovni član začne na isti lokaciji v pomnilniku. Podatkovni člani, tako kot v strukturah, niso nujno primitivne vrednosti in so dejansko lahko strukture ali celo druge unije.
Glavna uporaba unije je omogočanje dostopa do skupne lokacije z različnimi podatkovnimi tipi, na primer dostop do vhodnoizhodne strojne opreme, skupna raba bitnih polj in besed, alitipsko sprevračanje (type punning). Unije lahko zagotovijo tudi nizko stopnjopolimorfizma. Vendar ni tipskega preverjanja, zato mora programer zagotoviti, da se v različnih kontekstih dostopa do ustreznih polj. Ustrezno polje spremenljivke unije je običajno določeno s stanjem drugih spremenljivk, po možnosti v obdajajoči strukturi.
En pogost programski idiom, ki ga C uporablja z unijami za izvajanje tega, kar C++ imenujereinterpret_cast, z dodelitvijo enemu polju unije in branjem iz drugega, kot je storjeno v kodi, ki je odvisna od neobdelane predstavitve vrednosti. Praktični primer jemetoda računanja kvadratnih korenov z uporabo reprezentacije IEEE. Vendar to ni varna uporaba unij na splošno.
Strukture in unije imajo enako skladnjo. V C++ so unije načeloma bolj zaradi združljivosti za nazaj s C.[66]
Ena od najpomembnejših funkcij programskega jezika je zagotovitev pripomočkov zaupravljanje pomnilnika in objektov, ki so shranjeni v njem. C zagotavlja tri glavne načine dodelitve pomnilnika objektom:[48]
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.
samodejni: začasni objekti se lahko shranijo nasklad, 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 stamalloc 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, samodejna 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. Samodejna 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 samodejna 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 samodejne dodelitve pred standardom C99) fiksno velikost med prevajanjem, je velikokrat potrebna dinamična dodelitev.[48] Pred standardom C99 so bila polja s spreminjajočo velikostjo običajen primer tega. (Glej članek o funkcijimalloc za primer dinamično dodeljenih polj.) Z razliko od samodejne 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 zaznapovezovalnik alinalagalnik (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. Samodejnim 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, katerikolibitni vzorec, ki se nahaja vpomnilniku, 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 takonapač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 dosega ali se prepiše preko preden je klicana funkcijafree, oziroma se izrecno ponovno dodeli, potem se tisti del pomnilnika ne more obnoviti za kasnejšo ponovno rabo in je dejansko za program izgubljen. Ta pojav je znan kotpušč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.
Osnovno razširitev jezika C predstavljajoknjižnice. Knjižnica je v C množica funkcij zbrana v eni »arhivski«datoteki. Vsaka knjižnica ima po navadizaglavno 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 zahtevaprevajalnikove zastavice (na primer-lm, okrajšano za »poveži z matematično knjižnico«(link the math library)).[48]
Najobičajnejša knjižnica C jestandardna knjižnica jezika C, ki jo navajata standardaISO inANSI C. Standardna knjižnica je del vsake izvedbe C. Izvedbe, ki ciljajo na omejena okolja, kot so na primervgradni sistemi, lahko zagotavljajo le podmnožico standardne knjižnice. Standardna knjižnica C podpira vhodnoizhodni tok, dodelitev pomnilnika, matematične funkcije in količine, znakovne nize in časovne vrednosti. Več ločenih standardnih zaglavnih datotek (na primerstdio.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 zaUnix insisteme podobne Unix, še posebej funkcije, ki zagotavljajo vmesnik zajedro. Te funkcije v podrobnosti navajajo standardi, kot staPOSIX inSingle 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činkovitoobjektno kodo. Programerji nato naredijo vmesnike h knjižnici, tako da se lahko njeni podprogrami rabijo v visokonivojskih jezikih, kot sojava,Perl inPython.[48]
Datotečni vhod in izhod nista del samega jezika C, temveč ju upravljajo knjižnice (kot je standardna knjižnica C) in z njimi povezane zaglavne datoteke (na primerstdio.h). Obravnavanje datotek se na splošno izvaja prek V/I na visoki ravni, ki deluje prektokov (streams). Tok je s tega vidika tok podatkov, ki je neodvisen od naprav, medtem ko je datoteka konkretna naprava. V/I na visoki ravni poteka prek povezave toka z datoteko. V standardni knjižnici C semedpomnilnik (pomnilniško območje ali čakalna vrsta) začasno uporablja za shranjevanje podatkov, preden se pošljejo na končni cilj. To skrajša čas čakanja na počasnejše naprave, na primertrdi disk alinegibljivi disk (SSD). Vhodnoizhodne funkcije nizke ravni niso del standardne knjižnice C, ampak so na splošno del »golega«programiranja (programiranja, ki je neodvisno od katerega koli operacijskega sistema, kot je večinavdelanega programiranja). Z nekaj izjemami izvedbe vključujejo nizkonivojski V/I.
Za pomoč programerjem v C pri iskanju in popravljanju stavkov z neopredeljenim 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 orodjelint. Njegov razvoj je vodil do nastanka mnogih drugih.
Avtomatizirano preverjanje izvorne kode in pregledovanje 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 konstruktih, ki bodo verjetno dejansko napake.MISRA C je lastniška množica navodil v izogib takšni vprašljivi kodi, razvita za vgradne sisteme.[67]
C se pogosto uporablja zasistemsko programiranje pri izvajanju operacijskih sistemov in vgrajenih sistemskih aplikacij.[68] To je iz več razlogov:
C omogoča dostop do platformske strojne opreme in pomnilnika s kazalci intipsko sprevračanje, tako da je mogoče sistemsko specifične funkcije (npr.nadzornostatusne registre,vhodnoizhodne registre) konfigurirati in uporabljati s kodo, napisano v C– to popoln nadzor nad platformo, na kateri se izvaja.
koda, ustvarjena po prevajanju, ne zahteva velikosistemskih gradnikov in jo je mogoče priklicati iz neke zagonske kode na enostaven način– preprosto jo je izvesti.
stavki in izrazi v C se običajno dobro preslikajo v zaporedja navodil za ciljni procesor in zato je sistemska poraba v časuizvajanja nizka– izvajanje je hitro.
s svojim bogatim naborom operatorjev lahko C uporablja mnoge funkcije ciljnih procesorjev. Kjer ima določena CPE bolj ezoterična navodila, je mogoče sestaviti jezikovno različico z mordaintrinzičnimi funkcijami za izkoriščanje teh navodil– uporablja lahko praktično vse funkcije ciljne CPE.
C omogoča preprosto prekrivanje struktur na bloke dvojiških podatkov, kar omogoča razumevanje podatkov, navigacijo in spreminjanje– lahko zapiše podatkovne strukture, celo datotečne sisteme.
C podpira bogat nabor operatorjev, vključno z bitno manipulacijo, za celoštevilsko aritmetiko in logiko ter morda različne velikosti števil s plavajočo vejico– lahko učinkovito obdela ustrezno strukturirane podatke.
C je dokaj majhen jezik z le peščico stavkov in brez preveč gradnikov, ki ustvarjajo obsežno ciljno kodo– je razumljiv.
C ima neposreden nadzor nad dodelitvijo in ponovno dodelitvijo (sprostitvijo) pomnilnika, kar zagotavlja razumno učinkovitost in predvidljiv časovni razpored za operacije obravnavanja pomnilnika, brez kakršnih koli skrbi za občasne dogodke zbiranja smeti obzaustavitvi sveta– ima predvidljivo delovanje.
odvisno od povezovalnika in okolja lahko koda C kliče tudi knjižnice, napisane vzbirnem jeziku, in se lahko kliče iz zbirnega jezika– dobro deluje z drugo nizkopnivojsko kodo.
C in njegovidogovori o klicanju ter povezovalnikove strukture se običajno uporabljajo v povezavi z drugimi visokonivojskimi jeziki, pri čemer so podprti klici v C in iz C– dobro deluje z drugo visokonivojsko kodo.
C ima zelo zrel in širok ekosistem, vključno s knjižnicami, ogrodji, odprtokodnimi prevajalniki, razhroščevalniki in pripomočki, in je de facto standard. Verjetno gonilniki že obstajajo v C ali pa obstaja podobna arhitektura CPE kot zaledje prevajalnika C, zato je manj spodbude za izbiro drugega jezika.
C programerjem omogoča ustvarjanje učinkovitih izvedb algoritmov in podatkovnih struktur, ker je plast abstrakcije iz strojne opreme tanka, njeni stroški pa nizki, kar je pomembno merilo za računalniško intenzivne programe. Na primer,GNU Multiple Precision Arithmetic Library (GMP),GNU Scientific Library (GSL),Mathematica inMATLAB so v celoti ali delno napisani v C. Mnogi jeziki podpirajo klicanje knjižniških funkcij v C. OgrodjeNumPy, ki temelji naPythonu, na primer uporablja C za vidike visoke zmogljivosti in interakcije s strojno opremo.
Računalniške igre so pogosto zgrajene iz kombinacije jezikov. C se je zelo izkazal, zlasti za tiste igre, ki poskušajo doseči najboljšo zmogljivost računalniških platform. Med te igre spada igraDoom iz leta 1993.[69]
C se včasih uporablja kotvmesni jezik pri izvedbah drugih jezikov. Ta pristop se lahko uporablja zaradi prenosljivosti ali udobja. Z uporabo C kot vmesnega jezika dodatni strojnospecifični generatorji kode niso potrebni. C ima nekaj gradnikov, kot so predprocesorski ukazi številk vrstic in neobvezne odvečne vejice na koncu seznamov dodeljevalnikov, ki podpirajo prevajanje ustvarjene kode. Vendar pa so nekatere pomanjkljivosti C-ja spodbudile razvoj drugih jezikov, kitemeljijo na C-ju in so posebej zasnovani za uporabo kot vmesni jeziki, kot jeC--. Poleg tega imata sodobna glavna prevajalnikaGCC inLLVMvmesno reprezentacijo, ki ni C, in ti prevajalniki podpirajo čelne dele za mnoge jezike, vključno s C.
Posledica široke razpoložljivosti in učinkovitosti jezika C je, da so prevajalniki, knjižnice intolmači drugih programskih jezikov pogosto izvedeni v C.[70] Na primer,referenčne izvedbe Pythona,[71]Perla,[72]Rubyja[73] inPHP[74] so napisane v C.
V preteklosti se je C včasih uporabljal zaspletni razvoj z uporaboskupnega prehodnega vmesnika (CGI) kot »prehoda«za informacije med spletno aplikacijo,spletnim strežnikom inspletnim brskalnikom.[75] C je bil morda izbran namesto tolmačenih jezikov zaradi njegove hitrosti, stabilnosti in skoraj univerzalne dostopnosti.[76] Ni več običajna praksa, da se spletni razvoj izvaja v C,[77] zanj so priljubljeni mnogi drugi jeziki. Aplikacije, kjer se spletni razvoj na osnovi C nadaljuje, vključujejo konfiguracijske straniHTTP nausmerjevalnikih, napravahinterneta stvari (IoT) in podobno, čeprav imajo tudi tukaj nekateri projekti dele v višjenivojskih jezikih, npr. uporaba jezikaLua znotraj odkprtokodnega projektaOpenWRT.
Dva najbolj priljubljenaspletna strežnika,strežnik HTTP Apache innginx, sta oba napisana v C. Ti spletni strežniki komunicirajo z operacijskim sistemom, poslušajo vrata TCP za zahteve HTTP in nato strežejo statično spletno vsebino ali povzročijo izvajanje obdelave drugih jezikov za 'upodabljanje' vsebine, kot je PHP, ki je sam primarno napisan v C. C-jev surovi pristop omogoča konstrukcijo teh visoko zmogljivih programskih sistemov.
C se pogosto uporablja tudi za izvajanje aplikacij zakončne uporabnike.[7] Vendar pa je takšne aplikacije mogoče napisati tudi v novejših višjenivojskih jezikih.
Čeprav je bil C priljubljen, vpliven in izjemno uspešen, ima naslednje slabosti:
standardno obravnavanjedinamičnega pomnilnika s funkcijamamalloc infree je nagnjena k napakam. Napake vključujejo:puščanje pomnilnika, ko je pomnilnik dodeljen, vendar ni sproščen, in dostop do predhodno sproščenega pomnilnika (obviseli kazalci).[79]
uporaba kazalcev in neposredna manipulacija pomnilnika pomenita, da je možna poškodba pomnilnika, morda zaradi napake programerja ali nezadostnega preverjanja slabih podatkov.
ker koda, ki jo ustvari prevajalnik, sama vsebuje malo preverjanj, je programer obremenjen z upoštevanjem vseh možnih izidov, zaščito predprekoračitvami medpomnilnika, preverjanji meja polj,preplavljanji sklada, izčrpanostjo pomnilnika in upoštevanjemtekmovalnih pogojev, izolacijo niti itd.
uporaba kazalcev in njihova manipulacija med izvajanjem pomenita, da lahko obstajata dva načina za dostop do istih podatkov (prekrivanje (aliasing)), ki ju med prevajanjem ni mogoče določiti. To pomeni, da nekatere optimizacije, ki so morda na voljo za druge jezike, niso mogoče v C.Fortran v tem smislu velja za hitrejšega.
C nima standardne podpore zaobravnavanje izjem in ponuja lepovratne kode za preverjanje napak. Funkciji standardne knjižnicesetjmp inlongjmp sta bili uporabljeni za izvedbo mehanizma poskusnega ulova prek makrov.[84]
Za nekatere namene so bili sprejeti omejeni slogi C-ja, na primerMISRA C aliCERT C, da bi zmanjšali možnosthroščev.Podatkovne zbirke, kot jeCWE, poskušajo prešteti načine, na katere ima C itd. ranljivosti, skupaj s priporočili za ublažitev.
Obstajajoorodja, ki lahko ublažijo nekatere pomanjkljivosti. Sodobni prevajalniki C vključujejo preverjanja, ki lahko ustvarijo opozorila za pomoč pri prepoznavanju mnogih morebitnih hroščev.
Nekatere od teh pomanjkljivosti so spodbudile izdelavo drugih jezikov.
Java še zdaleč ni prvi poskus prenosljivosti. Ne pozabimo, da je bila prvotna motivacija za jezik C v zgodnjih 1970-ih ustvariti prenosni računalniški jezik. Teorija je bila, da bi lahko programer vzel program, napisan v C, in ga lahko pognal na različnih računalnikih preprosto s ponovnim prevajanjem izvorne kode. In v ta namen je bil C izjemno uspešen. Imam veliko programov, ki jih je mogoče prevesti in izvajati v sistemu Windows, na delovnih postajah Unix, ki temeljijo na Intelu, in celo na strežnikih Sun Ultra-SPARC. Ena od prednosti jave pred C-jem naj bi bila ta, da bi se programi lahko selili iz računalnika v računalnik, ne da bi jih bilo treba znova prevesti. Čeprav prenosljivost deluje večino časa, java ni in nikoli ne bo zamenjava za C ali njegovega naslednika C++.
Obstaja več tolmačev C ali skoraj C, vključno sCh inCINT, ki jih je mogoče uporabiti tudi za skriptiranje.
Ko soobjektno usmerjeni programski jeziki postali priljubljeni, sta bila C++ in Objective-C dve različni razširitvi jezika C, ki sta zagotavljali objektno usmerjene zmogljivosti. Oba jezika sta bila prvotno izvedena kotprevajalnika od vira do vira– izvorna koda je bila prevedena v C in nato prevedena s prevajalnikom C.[91]
Programski jezikC++ (prvotno imenovan »C zrazredi«) je zasnovalBjarne Stroustrup kot pristop k zagotavljanju objektno usmerjene funkcionalnosti s skladnjo, podobno C-ju.[92] C++ dodaja večjo moč tipizacije, doseg in druga orodja, uporabna pri objektno usmerjenem programiranju, ter omogočagenerično programiranje prek predlog (templates). C++ je trenutno skoraj supermnožica C in podpira večino C, z nekajizjemami.[92]
Objective-C je bil prvotno zelo »tanek«sloj na vrhu C-ja in ostaja strogasupermnožica C-ja, ki dovoljuje objektno usmerjeno programiranje z uporabo hibridne paradigme dinamične/statične tipizacije.[93][94][95] Objective-C izpeljuje svojo skladnjo iz C-ja inSmalltalka: skladnja, ki vključuje predprocesiranje, izraze, označitve funkcij in klice funkcij, je podedovana iz C-ja, skladnja za objektno usmerjene funkcije pa je bila prvotno vzeta iz Smalltalka.
↑Thompson je leta 1972 na kratko poskušal izdelati sistem, kodiran v zgodnji različici C (pred strukturami), vendar je zamisel opustil ( Ritchie (1993)).
↑Izvedli so več poskusov, da bi bilo v C postopanje zznakovnimi nizi manj nagnjeno k napakam. Ena strategija je dodajanje varnejših in uporabnejših funkcij, kot stastrdup 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 inBASIC omejeni model, ki ne vsebuje kazalcev. Vpaskalu so kazalci dinamični objekti, sam jezik pa ne dovoljuje kazalčne aritmetike.
↑Izvirna vzorčna koda se bo prevedla v večini sodobnih prevajalnikov, ki niso v načinu stroge standardne skladnosti, vendar ni v celoti v skladu z zahtevami C89 ali C99. C99 pravzaprav zahteva, da se ustvari diagnostično sporočilo.
↑Funkcijamain ima pravzaprav dva argumenta,int argc inchar *argv[], ki ju je mogoče uporabiti za obdelavoargumentov ukazne vrstice. Standard ISO C (§ 5.1.2.2.1) zahteva veljavnost obeh oblik funkcijemain, 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 funkcijamain samo s prvim parametrom:
intmain(intargc){/* ... */}
bo prevajalnik javil opozorilo, če pa se navede samo z drugim parametrom:
intmain(char*argv[]){/* ... */}
bo javil napako, ker mora sicer funkcijamain biti brez parametrov ali imeti strogo dva parametra, prvi parameter pa mora biti tipaint.
↑V nekaterih operacijskih sistemih, še posebej v starejših različicahUnixa, ima lahko funkcijamain tri parametre v obliki:
kjer je tretji parameter kazalec na vektor predvsem imen spremenljivk okolja. Tretji parameterenvp v funkcijimain pa ni v skladu s standardomPOSIX in se podatki o obstoječih spremenljivkah okolja pridobivajo z drugimi funkcijami, na primergetenv. Prevajalnikgcc zaLinux na primer to možnost podpira.
↑Argumentoma funkcijemain se lahko dodatno določi konstantnost:
To je priporočljivo, saj je možno zapisat na primer:
strcpy(argv[0],"brezveze");
kar želi spremeniti vrednost prvega znakovnega niza drugega argumenta, označenega kot konstantnega (./ime_programa).
↑Pred standardom C99 je bil na koncu funkcijemain zahtevan eksplicitni ukazreturn 0;.
12345Najmanjši obsegi do (na primer [−127, +127]) izhajajo iz različnih predstavitev celih števil, ki jih je dovolil standard (eniški komplement,predznačna velikost,dvojiški komplement).(GlejISO/IEC 9899:1999 specification, TC3(PDF) (v angleščini), str. 22, § 5.2.4.2.1Sizes of integer types <limits.h>) Vendar pa večina platform uporablja dvojiški komplement, kar za te implementacije implicira obseg v obliki do za, na primer [−128, +127] (SCHAR_MIN=−128 inSCHAR_MAX=+127) za 8-bitnisigned char. Od standarda C23 naprej je edina dovoljena predstavitev dvojiški komplement, zato se vrednosti gibljejo od do.(GlejISO/IEC 9899:2023 specification draft(PDF) (v angleščini), str. 41, § 6.2.6Representations of types)
12Velike črke se v izpisu razlikujejo od malih. Določilniki za velike črke ustvarijo vrednosti v velikih črkah, za male črke pa v malih (%A, %E, %F, %G ustvarijo vrednosti, kot so INF, NAN in E (eksponent) v velikih črkah).
12Mnogi dereferenčni operator* pišejo levostično s podatkovnim tipom in ne z imenom kazalca, pa redkeje tudi nestično od obeh:
12Verilog HDL (and C)(PDF) (v angleščini), The Research School of Computer Science at the Australian National University, 3. junij 2010, arhivirano izprvotnega spletišča(PDF) dne 6. novembra 2013, pridobljeno 19. avgusta 2013,1980s:; Verilog prvič predstavljen; na Verilog je vplival programski jezik C
↑»TR 18037: Embedded C«(PDF),open-std.org (v angleščini), ISO / IEC, 4. maj 2006,arhivirano(PDF) iz spletišča dne 25. februarja 2021, pridobljeno 26. julija 2011
Aimsiriwong, Opas (2016),Programming with C, Bangkok, Tajska: SE-EDUCATION PUBLIC COMPANY LIMITED, str.225–230,ISBN978-616-08-2740-4 (เอี่ยมสิริวงศ์, โอภาศ)
Dawkins, Kyle (1. januar 2006),Examining Objective-C (v angleščini), pridobljeno 13. oktobra 2014,Objective-C je objektno usmerjena stroga supermnožica C
Dowling, Clay (1. marec 2005),Using C for CGI Programming (v angleščini), linuxjournal.com,arhivirano iz spletišča dne 13. februarja 2010, pridobljeno 4. januarja 2010
Feuer, Alan R. (1998),The C Puzzle Book (1.izd.), Addison-Wesley,ISBN978-0-201-60461-0
Harbison, Samuel P.; Steele, Guy Lewis (2002),C: A Reference Manual (5.izd.), Englewood Cliffs, New Jersey: Prentice Hall,COBISS3299924,ISBN0-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 skladnjoBNF za C.
Kernighan, Brian Wilson; Ritchie, Dennis (1988),The C Programming Language (2.izd.), Upper Saddle River, New Jersey: Prentice Hall,COBISS519902,ISBN0-13-110362-8, ANSI C.
Kim, Eugene Eric (november–december 1995),»Programming CGI in C«,Dr. Dobb's Sourcebook, Miller Freeman, Inc., pridobljeno 12. marca 2025{{citation}}: Vzdrževanje CS1: samodejni prevod datuma (povezava)
Rauchwerger, Lawrence (2004),Languages and compilers for parallel computing: 16th international workshop, LCPC 2003, College Station, TX, USA, October 2–4, 2003: revised papers, Springer,ISBN978-3540246442,OCLC57965544
Stroustrup, Bjarne (2002).Sibling rivalry: C and C++(PDF) (poročilo) (v angleščini). AT&T Labs.Arhivirano(PDF) iz spletišča dne 24. avgusta 2014. Pridobljeno 24. avgusta 2014.