Zašto programski jezik C i dalje vlada

Nijedna se tehnologija ne zadržava 50 godina ako svoj posao ne obavlja bolje od većine bilo čega drugog - posebno računalna tehnologija. Programski jezik C živi i djeluje od 1972. godine i još uvijek vlada kao jedan od temeljnih gradivnih dijelova našeg softverski definiranog svijeta.

Ali ponekad se tehnologija zalijepi jer ljudi jednostavno nisu stigli zamijeniti je. Tijekom posljednjih nekoliko desetljeća pojavili su se deseci drugih jezika - neki su izričito osmišljeni kako bi osporili C-ovu dominaciju, a neki su odsjekli C sa strane kao nusprodukt njihove popularnosti.

Nije teško tvrditi da C treba zamijeniti. Istraživanje programskog jezika i prakse razvoja softvera nagovještavaju kako postoje daleko bolji načini za napraviti od C-ovog načina. Ali C ustraje svejedno, iza čega su desetljeća istraživanja i razvoja. Malo koji drugi jezik može ga pobijediti zbog performansi, kompatibilnosti bez metala ili sveprisutnosti. Ipak, vrijedi vidjeti kako se C postavlja protiv jezičnog natjecanja velikih imena u 2018. godini.

C nasuprot C ++

Prirodno, C se najčešće uspoređuje sa C ++, jezikom koji je - kao što i samo ime govori - stvoren kao produžetak C. Razlike između C ++ i C mogu se okarakterizirati kao opsežne ili  pretjerane , ovisno o tome koga tražite.

Iako je još uvijek sličan C-u u svojoj sintaksi i pristupu, C ++ nudi mnoge zaista korisne značajke koje izvorno nisu dostupne u jeziku C: prostore imena, predloške, iznimke, automatsko upravljanje memorijom i tako dalje. Projekti koji zahtijevaju vrhunsku izvedbu - baze podataka, sustavi strojnog učenja - često se pišu na C ++-u koristeći te značajke kako bi se istrgnuo svaki pad performansi iz sustava.

Nadalje, C ++ se nastavlja širiti mnogo agresivnije od C. Nadolazeći C ++ 20 donosi još više tablice, uključujući module, podprograme, sinkronizacijsku knjižnicu i koncepte, što čini predloške lakšima za upotrebu. Posljednja revizija C standarda dodaje malo i usredotočuje se na zadržavanje povratne kompatibilnosti.

Stvar je u tome što svi plusevi u C ++-u mogu raditi i kao minusi. Velike. Što više C ++ značajki koristite, to više složenosti uvodite i sve je teže ukrotiti rezultate. Programeri koji se ograniče na podskup C ++-a mogu izbjeći mnoge njegove najgore zamke i ekscese. Ali neke se trgovine žele zaštititi od složenosti C ++-a. Pridržavanje C prisiljava programere da se ograniče na taj podskup. Na primjer, tim za razvoj jezgre Linuxa izbjegava C ++.

Odabir C-a preko C ++-a način je za vas - i za sve programere koji održavaju kôd nakon vas - kako biste izbjegli da se petljate s prekomjernim C ++-om, prihvaćajući prisilni minimalizam. Naravno, C ++ s bogatim razlogom ima bogat skup značajki na visokoj razini. Ali ako minimalizam bolje odgovara trenutnim i budućim projektima - i projektnim timovima - tada C ima više smisla.

C naspram Jave

Nakon desetljeća Java ostaje glavna komponenta za razvoj softvera za poduzeća - i glavni proizvod za razvoj općenito. Mnogi najznačajniji projekti softvera za poduzeća napisani su na Javi - uključujući veliku većinu projekata Apache Software Foundation - a Java ostaje održiv jezik za razvoj novih projekata sa zahtjevima poduzeća.

Sintaksa Java posuđuje u velikoj mjeri od C i C ++. Za razliku od C-a, Java se prema zadanim postavkama ne kompajlira u izvorni kôd. Umjesto toga, Java runtime okruženje, JVM, JIT (upravo u vremenu) kompajlira Java kôd za pokretanje u ciljnom okruženju. U pravim okolnostima JITted Java kôd može se približiti ili čak premašiti izvedbu C.

Filozofija "napiši jednom, pokreni bilo gdje" koja stoji iza Jave također omogućava Java programima da se izvode s relativno malo podešavanja za ciljanu arhitekturu. Suprotno tome, iako je C prebačen na veliki broj arhitektura, bilo kojem C programu možda će trebati prilagodba kako bi se ispravno izvodio na, recimo, Windowsu ili Linuxu.

Ova kombinacija prenosivosti i snažnih performansi, zajedno s masivnim ekosustavom softverskih knjižnica i okvira, čine Javu pristupnim jezikom i vremenom izvođenja za izgradnju poslovnih aplikacija.

Gdje Java zaostaje za C, područje je u kojem se Java nikada nije trebala natjecati: trčanje blizu metala ili izravni rad s hardverom. C kôd se kompajlira u strojni kôd, koji postupak izvodi izravno. Java se kompajlira u bytecode, koji je posredni kôd koji JVM interpreter zatim pretvara u strojni kod. Nadalje, iako je Javino automatsko upravljanje memorijom u većini slučajeva blagoslov, C je prikladniji za programe koji moraju optimalno koristiti ograničene resurse memorije.

Međutim, postoje neka područja u kojima se Java može približiti C-u u smislu brzine. JVM-ov JIT engine optimizira rutine tijekom izvođenja na temelju ponašanja programa, omogućavajući mnoge klase optimizacije koje nisu moguće s unaprijed kompiliranim C. I dok Java runtime automatizira upravljanje memorijom, neke novije aplikacije zaobilaze to. Na primjer, Apache Spark djelomično optimizira obradu u memoriji korištenjem prilagođenog koda za upravljanje memorijom koji zaobilazi JVM.

C nasuprot C # i .Net

Gotovo dva desetljeća nakon njihovog uvođenja, C # i .Net Framework ostaju glavni dijelovi poslovnog softverskog svijeta. Rečeno je da su C # i .Net bili Microsoftov odgovor na Javu - upravljani sustav za kompajliranje koda i univerzalno vrijeme izvođenja - a toliko usporedbi između C i Jave također drži za C i C # /. Net.

Poput Jave (i donekle Pythona), .Net nudi prenosivost na različitim platformama i golem ekosustav integriranog softvera. To nisu male prednosti s obzirom na to koliko se razvoj usmjeren na poduzetništvo odvija u .Net svijetu. Kada razvijete program na jeziku C # ili bilo kojem drugom .Net jeziku, moći ćete se oslanjati na svemir alata i knjižnica napisanih za vrijeme izvođenja .Net. 

Još jedna .NET-ova prednost nalik Javi je JIT optimizacija. Programi C # i .Net mogu se sastaviti i prije vremena prema C-u, ali uglavnom se prikupljaju u vrijeme izvođenja .Net-a i optimiziraju s informacijama o vremenu izvođenja. JIT kompilacija omogućuje sve vrste optimizacija na mjestu za pokrenuti .Net program koji se ne može izvesti u C.

Poput C, C # i .Net pružaju razne mehanizme za izravni pristup memoriji. Hrpi, stogu i neupravljanoj sistemskoj memoriji dostupni su putem .Net API-ja i objekata. A programeri mogu koristiti unsafenačin rada u .Netu kako bi postigli još veće performanse.

Ipak, ništa od toga ne dolazi besplatno. Upravljani objekti i unsafepredmeti ne mogu se proizvoljno razmjenjivati, a međusobno razvrstavanje ima cijenu izvedbe. Stoga maksimiziranje performansi .Net aplikacija znači svod na minimum između upravljanih i neupravljanih objekata.

Kada si ne možete priuštiti plaćanje kazne za upravljanu i neupravljanu memoriju ili kada je .Net vrijeme izvođenja loš izbor za ciljno okruženje (npr. Prostor jezgre) ili možda uopće nije dostupno, tada je C ono što potreba. I za razliku od C # i .Net, C prema zadanim postavkama otključava izravan pristup memoriji. 

C protiv Go

Sintaksa Go duguje C-kovrčavim zagradama kao graničnicima, izrazima koji se završavaju zarezom i tako dalje. Programeri koji poznaju C obično mogu bez većih poteškoća uskočiti u Go, čak i uzimajući u obzir nove Go značajke poput prostora imena i upravljanja paketima.

Čitajući kôd bio je jedan od Goovih vodećih dizajnerskih ciljeva: olakšati programerima da ubrzaju bilo koji Go projekt i postanu vješti u bazi koda u kratkom redoslijedu. C baze baza kodova teško je napipati, jer su sklone pretvaranju u pacovo gnijezdo makronaredbi i #ifdefspecifičnih za projekt i zadani tim. Go's sintaksa i njezini ugrađeni alati za formatiranje koda i upravljanje projektima trebali bi zadržati takve institucionalne probleme.

Go također sadrži dodatke poput goroutina i kanala, alate na razini jezika za rukovanje istodobnošću i prosljeđivanje poruka između komponenata. C bi zahtijevao da se takve stvari ručno valjaju ili isporučuju iz vanjske knjižnice, ali Go ih nudi odmah, što olakšava konstrukciju softvera koji ih treba.

Go se razlikuje od C ispod haube u upravljanju memorijom. Go objektima se automatski upravlja i skuplja se smeće prema zadanim postavkama. Za većinu poslova programiranja ovo je izuzetno povoljno. Ali to također znači da će bilo koji program koji zahtijeva determinističko rukovanje memorijom biti teže napisati.

Go sadrži unsafepaket za zaobilaženje nekih Go-ovih tipova sigurnosti, poput čitanja i pisanja proizvoljne memorije s Pointertipom. Ali unsafedolazi s upozorenjem da programi napisani s njim "možda nisu prenosivi i nisu zaštićeni smjernicama za kompatibilnost Go 1".

Go je pogodan za izgradnju programa poput uslužnih programa naredbenog retka i mrežnih usluga, jer im rijetko trebaju takve finoće. No, upravljačke programe niske razine, komponente operativnog sustava u prostoru jezgre i druge zadatke koji zahtijevaju strogu kontrolu nad rasporedom i upravljanjem memorijom najbolje je stvoriti u C.

C protiv hrđe

Rust je na neki način odgovor na zagonetke upravljanja memorijom koje su stvorili C i C ++, kao i na mnoge druge nedostatke tih jezika. Rust se kompajlira u izvorni strojni kôd, tako da se s obzirom na performanse smatra jednakim C-u. Sigurnost memorije prema zadanim postavkama je glavna stvar Rusta.

Rustova pravila sintakse i kompilacije pomažu programerima da izbjegnu uobičajene greške u upravljanju memorijom. Ako program ima problem s upravljanjem memorijom koji prelazi sintaksu Rust, jednostavno se neće kompajlirati. Novopridošli u jezik, posebno s jezika poput C koji pruža dovoljno prostora za takve bugove, provode prvu fazu svog obrazovanja o Rustu učeći kako smiriti kompajler. No, zagovornici Rust-a tvrde da ova kratkoročna bol ima dugoročnu isplatu: sigurniji kôd koji ne žrtvuje brzinu.

Rust svojim alatom poboljšava i C. Upravljanje projektima i komponentama dio je lanca alata koji se prema zadanim postavkama isporučuje s Rustom, kao i s Go. Postoji zadani, preporučeni način upravljanja paketima, organiziranja mapa projekata i rješavanja mnogih drugih stvari koje su u C-u u najboljem slučaju ad-hoc, a svaki projekt i tim ih rješavaju drugačije.

Ipak, ono što se u Rustu naziva prednost, možda se C programeru ne čini kao nešto. Rustove sigurnosne značajke tijekom kompajliranja ne mogu se onemogućiti, tako da čak i najtravijalniji Rust program mora biti u skladu s Rustovim sigurnosnim strogim memorijama. C je možda prema zadanim postavkama manje siguran, ali je puno fleksibilniji i oprašta kad je to potrebno.

Drugi mogući nedostatak je veličina jezika Rust. C ima relativno malo značajki, čak i kad se uzme u obzir standardna knjižnica. Skup značajki Rust širi se i nastavlja rasti. Kao i kod C ++-a, veći skup značajki Rust znači veću snagu, ali i veću složenost. C je manji jezik, ali to je puno lakše mentalno modelirati, pa je možda bolje prilagođen projektima u kojima bi Rust bio pretjeran.

C nasuprot Pythonu

Ovih dana, kad god se govori o razvoju softvera, čini se da Python uvijek ulazi u razgovor. Napokon, Python je "drugi najbolji jezik za sve" i nesumnjivo jedan od najsvestranijih, s tisućama dostupnih biblioteka trećih strana.

Ono što Python naglašava i gdje se najviše razlikuje od C, daje prednost brzini razvoja u odnosu na brzinu izvršenja. Program koji bi mogao potrajati sat vremena za sastavljanje na nekom drugom jeziku - poput C - mogao bi se sastaviti u Pythonu za nekoliko minuta. S druge strane, izvršavanju tog programa na C jeziku trebaju sekunde, ali u Pythonu minuta. (Dobro pravilo: Python programi obično rade red veličine sporije od svojih kolega C.) Ali za mnoge poslove na modernom hardveru Python je dovoljno brz, a to je bilo ključno za njegovo prihvaćanje.

Druga velika razlika je upravljanje memorijom. Python programima u potpunosti upravlja memorija pomoću Python runtimea, tako da se programeri ne moraju brinuti o glatkoj dodjeli i oslobađanju memorije. Ali opet, lakoća za programere dolazi po cijenu izvedbe. Pisanje C programa zahtijeva pažljivu pozornost na upravljanje memorijom, ali rezultirajući programi često su zlatni standard za čistu brzinu stroja.

Ispod kože, Python i C dijele duboku vezu: referentno vrijeme izvršavanja Pythona napisano je na C. To omogućuje Python programima da zamotaju knjižnice napisane na C i C ++. Značajni dijelovi Python ekosustava neovisnih knjižnica, poput strojnog učenja, imaju u osnovi C kod.

Ako je brzina razvoja važnija od brzine izvršavanja i ako se većina izvedbenih dijelova programa može izolirati u samostalne komponente (za razliku od širenja po kodu), ili čisti Python ili kombinacija Python i C knjižnica čine bolji izbor od samog C. Inače, C i dalje vlada.