Мо́ва праграмава́ння (вымаўляецца: Сі́) — стандартызаваная імператыўная мова праграмавання, створаная на пачатку 1970-х гадоў Кенам Томпсанам і Дэнісам Рычы для аперацыйнай сістэмы UNIX. Потым яна была перанесена на іншыя аперацыйныя сістэмы, і цяпер з’яўляецца адной з найбольш ужывальных моў праграмавання. Мове C часта аддаюць перавагу за яе эфектыўнасць, і гэта адна з самых пашыраных моў сістэмнага праграмавання, хоць з яе дапамогай можна пісаць і праграмы агульнага прызначэння. Яна часта выкарыстоўваецца пры навучанні праграмаванню, хоць стваралася не для пачаткоўцаў.
Асноўныя рысы
Агляд C — адносна мінімалістычная мова праграмавання, бліжэйшая да апаратнага забеспячэння і мовы асэмблера, чым іншыя мовы праграмавання высокага ўзроўню. Сапраўды, C часам называюць «пераносным асэмблерам», паказваючы яго адрозненні ад моў праграмавання нізкага ўзроўню, напрыклад, асэмблера: код на C можна скампіляваць і выканаць на амаль любым камп’ютары, а код на асэмблеры можна выконваць толькі на той мадэлі камп’ютара, для якой ён напісаны. Таму мову C называюць мовай сярэдняга ўзроўню.
Пры распрацоўцы C асноўнай мэтай было стварэнне працэдурнай мовы праграмавання, якая дазволіла б пісаць праграмы з меншай колькасцю памылак, не ствараючы пры гэтым дадатковых цяжкасцей для аўтараў кампілятараў складанымі асаблівасцямі мовы. Такім чынам, у C ёсць такія важныя рысы:
Простая моўная база, у якой важныя функцыі, падобныя да матэматычных і файлавых, рэалізуюцца з дапамогай бібліятэк Засяроджанне на парадыгме працэдурнага праграмавання, з магчымасцямі праграмавання ў структурным стылі Простая сістэма тыпаў, якая не дапускае замнога безсэнсоўных аперацый Выкарыстанне мовы прэпрацэсара C, напрыклад, для стварэння макрасаў ці ўключэння частак кода Нізкаўзроўневы доступ к памяці праз выкарыстанне указальнікаў Невялікая колькасць ключавых слоў Параметры функцый заўсёды перадаюцца па значэнні, а не па спасылцы Указальнікі на функцыі, з дапамогай якіх ствараецца простая форма полімарфізму Вобласці дзеяння зменных Структуры (запісы), ці ствараемыя праграмістам састаўныя тыпы даных (struct), якія дазваляюць спалучаць даныя і кіраваць звязанай інфармацыяй як адзіным цэлым
Рысы іншых моў, якіх не хапае ў C: Бяспечнасць тыпаў Аўтаматычная зборка смецця Класы ці аб’екты з пэўнымі паводзінамі Развітая сістэма тыпаў Укладзеныя функцыі Універсальнае праграмаванне Перагрузка аператараў Падтрымка шматніцевасці і камп’ютарных сетак
Хоць спіс адсутных у C зручных канструкцый доўгі, іх адсутнасць дапамагла прыняць C, бо кампілятары для новых платформ пісаліся хутчэй, і праграмістам было лягчэй зразумець, што робіць той ці іншы код, і кантраляваць яго. Таму код на C часта выконваецца хутчэй за код на іншых мовах праграмавання.
Яшчэ адна з прычын шырокага выкарыстання C палягае ў тым, што кампілятары, бібліятэкі і інтэрпрэтатары іншых высокаўзроўневых моў часта ствараюцца на мове C.
Прыклад «hello, world»
Упершыню гэта простая праграма з’явілася ў першым выданні кнігі K&R і стала стандартнай уводнай праграмай у большасці падручнікаў па праграмаванні, незалежна ад мовы. Гэта праграма выводзіць «hello, world» у стандартны вывад, звычайна, ў тэрмінал ці на экран.
main() { printf("hello, world\n"); }
Прыведзеная вышэй праграма нармальна скампілюецца на большасці сучасных кампілятараў. Аднак пры кампіляцыі згодна са стандартам ANSI C будзе выдадзена некалькі папярэджанняў. Акрамя таго, код не скампілюецца, калі кампілятар дакладна выконвае стандарт C99, бо вяртаемае значэнне не будзе лічыцца значэннем тыпа int пры адсутнасці іншага. Усё гэта можна выправіць, дадаўшы некалькі невялікіх змяненняў у зыходную праграму:
#include <stdio.h>
int main(void) { printf("hello, world\n");
return(0); }
Разгледзім праграму па радках:
#include <stdio.h> Першы радок праграмы з’яўляецца дырэктывай прэпрацэсара, #include. Гэты тэкст паказвае, што прэпрацэсару — першай праграме, якая апрацоўвае зыходны файл пры кампіляцыі — трэба замяніць гэты радок на названы ў ім файл. У дадзеным выпадку гэта загаловачны файл, stdio.h, які апісвае стандартныя функцыі ўводу і вываду. Вуглавыя дужкі вакол stdio.h паказваюць, што файл трэба шукаць у папцы, пазначанай як шлях пошуку загаловачных файлаў.
int main(void) Наступны радок паказвае, што азначаецца функцыя пад назвай main. Функцыя main мае адмысловае значэнне ў праграмах на C. Калі выконваецца праграма, першай выклікаецца функцыя main(). Слова int паказвае, што вяртаемае значэнне — значэнне, якое будзе вылічана ў функцыі main — ёсць цэлым лікам (integer). Частка коду (void) паказвае, што функцыя main не прымае ніякіх аргументаў.
{ Тут фігурныя дужкі паказваюць месца, дзе пачынаецца код функцыі main.
printf("hello, world\n"); Гэты радок выклікае (г.зн. выконвае код і вяртаецца да далейшага выканання праграмы) функцыю з назвай printf, якая аб’яўлена ў загаловачным файле stdio.h. У гэтым выкліку функцыі printf перадаецца адзін аргумент, радок тэксту «hello, world\n». Спалучэнне сімвалаў «\n» называецца escape-паслядоўнасцю і пераўтвараецца ў сімвал EOL (end-of-line, канец радка), які пераводзіць курсор у тэрмінале на пачатак новага радка. Функцыя printf вяртае значэнне тыпу int, аднак мы яго не выкарыстоўваем, таму не пішам ніякага кода для яго апрацоўкі.
return(0); Гэты радок заканчвае выкананне функцыі main вяртаннем значэння 0.
} Гэта фігурная дужка паказвае канец кода функцыі main.
Ключавыя словы У стандарце С89 азначаны 32 ключавыя словы: auto double int structbreak else long switchcase enum register typedefchar extern return unionconst float short unsignedcontinue for signed voiddefault goto sizeof volatiledo if static while
Стандарт C99 дабаўляе пяць новых: _Bool, inline, _Complex, _Imaginary, restrict.
Тыпы
Тыпы ў C падобныя да тыпаў іншых пераемнікаў мовы ALGOL, такіх як Pascal, хоць яны і шмат у чым адрозніваюцца. Ёсць тыпы для цэлых лікаў розных памераў, знакавых і бяззнакавых, лікаў з плаваючай коскай, літар, пералічэнняў (enum), структур (struct) і аб’яднанняў (union), з дапамогай якіх можна захоўваць даныя некалькі тыпаў (але нельга захоўваць даныя двух розных тыпаў адначасова).
C вельмі часта выкарыстоўвае ўказальнікі і вельмі просты тып спасылак для захавання адрасоў памяці. Гэты адрас можна змяніць з дапамогай аператара прысвойвання ці арыфметыкі ўказальнікаў. Падчас выканання ўказальнік з’яўляецца адрасам у памяці, а падчас кампіляцыі — адрасам і тыпам даных, што дазваляе праверыць частку выразаў з указальнікамі падчас кампіляцыі. Указальнікі выкарыстоўваюцца ў C для розных мэт. Тэкставыя радкі звычайна прадстаўлены як указальнік на масіў сімвалаў. Дынамічнае выдзяленне памяці, якое апісана ніжэй, ажыццяўляецца з дапамогай указальнікаў.
Нулявы ўказальнік ёсць адмысловым указальнікам, які ўказвае на ячэйку памяці з адрасам 0. Працаваць напрамую з такім указальнікам нельга, звычайна яго выкарыстоўваюць, каб пазначыць неіснаванне пэўных аб’ектаў у памяці. Нулявыя ўказальнікі зручна выкарыстоўваць у адмысловых выпадках, напрыклад для запісу ўказальніку на наступны аб’ект у канцы спісу. Спробы звярнуцца да ячэйкі памяці, на якую ўказвае нулявы ўказальнік, можа прывесці да непрадбачаных вынікаўПры стварэнні звычайнай праграмы, хутчэй за ўсё, проста вылеціць сама праграма, і больш нічога. А вось пры распрацоўцы драйвера так можна зруйнаваць аперацыйную сістэму.. Указальнікі на тып void таксама існуюць, і паказваюць на аб’ект невядомага тыпу. Яны звычайна выкарыстоўваюцца ва ўніверсальным праграмаванні. Памер аб’екта, на які яны ўказваюць, невядомы, таму іх можна пераўтварыць ва ўказальнікі любога іншага тыпу.
Масівы ў C маюць нязменную даўжыню, якая вядома падчас кампіляцыі (праўда, у C99 былі дабаўлены масівы зменнай даўжыні); на практыцы, гэта не вельмі вялікая праблема, бо C дазваляе выдзяляць блокі памяці любой даўжыні ў час работы праграмы з дапамогай стандартнай бібліятэкі і выкарыстаць іх у якасці масіваў. У адрозненне ад іншых моў, у мове C масівы ёсць указальнікамі: як звычайны адрас у памяці і тып даных. Таму няма ніякіх праверак на выхад за межы масіву.
У мове C не прадугледжана адмысловых сродкаў падтрымкі мнагамерных масіваў, і мнагамерныя масівы азначаюцца зваротным чынам: як масівы масіваў. Так, напрыклад, двухмерны масіў ёсць масівам аднамерных масіваў, трохмерны — масівам двухмерных, і г.д. Увогуле кажучы, фізічнае ўладкаванне мнагамернага масіва у памяці камп’ютара залежыць ад таго, які гэты масіў: статычны ці дынамічны.
Мова C часта выкарыстоўваецца ў нізкаўзроўневым сістэмным праграмаванні, дзе можа ўзнікнуць неабходнасць разглядаць цэлы лік як адрас у памяці, лік з плаваючай коскай двайной дакладнасці як цэлы лік ці адзін тып указальнікаў як іншы. Для такіх выпадкаў у C есць пераўтварэнне тыпаў, з дапамогай якога выконваецца няяўны перавод аднаго значэння тыпу ў значэнне іншага тыпу. Няяўнае пераўтварэнне тыпаў можа быць небяспечным, бо часам працуе не так, як на першы погляд можна было б чакаць, і ў выніку прыводзіць да цяжка ўлоўных памылак.
Захоўванне даных
У мове C ёсць тры спосабы атрымаць памяць для аб’ектаў: Статычнае выдзяленне памяці: месца для аб’екта выдзяляецца ў двайковым выканальным файле падчас кампіляцыі. Пры запуску праграмы загрузчык адлюстроўвае гэтыя аб’екты ў аператыўную памяць; там яны знаходзяцца на працягу ўсяго існавання праграмы ў памяці. Аўтаматычнае выдзяленне памяці: часовыя аб’екты можна захоўваць у стэку, і месца, якое выкарыстоўваецца імі, аўтаматычна вызваляецца пасля таго, як завяршаецца выкананне блока, дзе яны выкарыстоўваліся Дынамічнае выдзяленне памяці: праграміст можа запрасіць блок памяці пажаданага памеру падчас выканання праграмы з дапамогай функцый malloc(), realloc() з вобласці памяці, якая называецца кучай; гэтыя блокі можна выкарыстоўваць ізноў, пасля таго як праграміст вярнуў іх з дапамогай функцыі free()
Кожны са шляхоў выдзялення памяці выкарыстоўваецца ў розных выпадках і мае свае перавагі і недахопы. Напрыклад, статычнае выдзяленне памяці не патрабуе выклікаў адмысловых працэдур, пры аўтаматычным выдзяленні кампілятар зменіць толькі адну сістэмную зменную, а для дынамічнага выдзялення памяці патрэбна шмат коду як з боку праграміста, так і з боку кампілятара. Аднак памяць стэка звычайна вельмі абмежаваная ў параўнанні з памяццю кучы, і толькі дынамічнае выдзяленне памяці дазваляе выдзяліць блок памяці, памер якога будзе вядомы толькі падчас выканання праграмы. У большасці праграм на С выкарыстоўваюцца ўсе тры шляхі.
Там, дзе гэта магчыма, лепей карыстацца аўтаматычным і статычным выдзяленнем памяці, бо пры іх выкарыстанні памяці выдзяляе кампілятар, і праграмісту не трэба пісаць код для выдзялення і вызвалення памяці, які часта прыводзіць да памылак. Аднак даволі часта памер структур даных змяняецца падчас выканання праграмы; для выкарыстання аўтаматычнага і статычнага выдзялення патрэбна ведаць памер падчас кампіляцыі, таму часта (напрыклад, пры стварэнні масіваў са зменнай даўжынёй) трэба выкарыстоўваць дынамічнае выдзяленне памяці.
Сінтаксіс
У адрозненні ад моў, падобных да Fortran 77, у C праграміст можа выкарыстоўваць прабелы і пераводы радкоў там, дзе пажадае. Каментары могуць быць: шматрадковымі: любы тэкст паміж першым з’яўленнем /* і да першага з’яўлення */; аднарадковымі (у C99): любы тэкст пасля // да канца радка.
Амаль любы зыходны файл утрымлівае аб’яўленні і азначэнні функцый. У сваю чаргу, азначэнні функцый змяшчаюць аб’яўленне і інструкцыі (прадпісанні). Аб’яўленні або азначаюць новыя тыпы з дапамогай ключавых слоў (падобных да struct, union, і enum), або ўводзяць новыя зменныя пэўных тыпаў і задаюць іхнія значэнні.
Прыклад: аб’яўленне структуры Пункт (Point) з дзвюма цэлымі каардынатамі (x, y) struct Point{ int x; int y;
Прыклад: аб’яўленне зменнай x тыпу «лік з плаваючай коскай двайной дакладнасці» double x;