C keele kiirkursus

Programmi ülesehitus

Põhimõtteliselt võib C-keele programmi kirjutada ükskõik mis kujul, kas või üherealisena, sest kompilaator eeldab vaid süntaksireeglite järgimist. Samas on selguse ja lihtsuse huvides ikkagi soovitatav tähelepanu pöörata ka programmikoodi stiilile. Tüüpiline C-keele programmi ülesehitus:

/* Päisefailide kaasamine */
#include <avr/io.h>
#include <stdio.h>
 
/* Makro-deklaratsioonid */
#define PI 3.141
 
/* Andmetüübid */
typedef struct
{
	int a, b;
}
element;
 
/* Globaalsed muutujad */
element e;
 
/* Funktsioonid */
int main(void)
{	
	// Lokaalsed muutujad
	int x;
 
	// Programm
	printf("Tere maailm!\n");
}

Kommentaarid

Programmi saab kirjutada teksti, mida ei kompileerita ja mis on programmeerijale abiks selgitamisel või märkmete tegemisel. Samuti saab kommentaare kasutada programmilõikude ajutiseks täitmisest kõrvaldamiseks. Näide kahte liiki kommentaaridest:

// Üherealine kommentaar.
// Kommentaariks loetakse kahe kaldkriipsu järel olevat teksti
 
/*
  Mitmerealine kommentaar
  Kommentaari algus ja lõpp määratakse kaldkriipsude ja tärnidega
*/

 

Andmed

Andmetüübid

C-keele baasandmetüübid:

Tüüp Miinimum Maksimum Bitte Baite
(signed) char -128 127 8 1
unsigned char 0 255 8 1
(signed) short -32768 32767 16 2
unsigned short 0 65535 16 2
(signed) long -2147483648 2147483647 32 4
unsigned long 0 4294967295 32 4
float -3.438 3.438 32 4
double -1.7308 1.7308 64 8

Sulgudes olevat sõna “signed” ei pea kasutama, kuna vaikimisi ongi andmetüübid bipolaarsed.

AVR mikrokontrolleril int = short
PC arvutil int = long

C-keeles puudub spetsiaalne teksti-andmetüüp. Selle asemel kasutatakse char tüüpi massiive (nendest edaspidi) ja ASCII “tähestikku”, kus igal tähel ja märgil on oma järjekorranumber.

Muutujad

Programmis saab kasutada kindlat andmetüüpi mälupesasid - muutujaid. Muutujate nimed võivad sisaldada ladina tähestiku tähti, numbreid ja alakriipsu. Nimi ei tohi alata numbriga. Muutuja deklareerimisel kirjutatakse selle ette andmetüüp. Väärtuse omistamiseks muutujale kasutatakse võrdusmärki (=). Näide muutujate kasutamisest:

char c; // char tüüpi muutuja c deklareerimine
 
c = 65; // Muutujale c väärtuse omistamine.
c = 'A'; // A on ASCII märgisüsteemis samuti väärtusega 65
 
// int tüüpi muutuja i20 deklareerimine ja algväärtustamine
int i20 = 55;
 
// Mitme unsigned short tüüpi muutuja deklareerimine
unsigned short x, y, test_variable;

Konstandid

Konstante deklareeritakse samamoodi nagu muutujaid, kuid ette lisatakse const võtmesõna. Konstantide väärtust ei saa programmi käigus muuta. Näide kasutamisest:

const int x_factor = 100; // int tüüpi konstandi määramine

Struktuurid

Baasandmetüüpidest saab struct võtmesõnaga struktuure koostada. Struktuur on justkui kombineeritud andmetüüp. Tüüpi deklareeritakse typedef võtmesõnaga. Näide struktuurist andmetüübi loomise ja kasutamise kohta:

// Uue punkti andmetüübi deklareerimine
typedef struct
{
	// x ja y koordinaat ning värvikood
	int x, y;
	char color;
}
point;
 
// Punkti muutuja deklareerimine
point p;
 
// Punkti koordinaatide määramine
p.x = 3;
p.y = 14;

Massiivid

Andmetüüpidest võib koostada massiive (jadasid). Massiiv võib olla ka mitmemõõtmeline (tabel, kuup, jne). Näide ühe- ja kahemõõtmelise massiivi kasutamisest:

// Ühe- ja kahemõõtmelise massiivi deklareerimine
char text[3];
int table[10][10];
 
// Teksti moodustamine märgimassiivist
text[0] = 'H';  // Täht
text[1] = 'i';  // Täht
text[2] = 0;    // Teksti lõpetamise tunnus (null-bait)
 
// Tabeli ühe elemendi muutmine
table[4][3] = 1;

Avaldised

Muutujate, konstantide ja väärtust tagastavate funktsioonidega saab koostada avaldisi (tehteid). Avaldise väärtusi saab omistada muutujatele, neid saab kasutada funktsiooni parameetritena ja erinevates tingimuslausetes.

Aritmeetilised

C-keeles toetatud aritmeetilised tehted on liitmine (+), lahutamine (-), korrutamine (*), jagamine (/) ja mooduli võtmine (%). Näited aritmeetiliste tehete kasutamisest:

int x, y;
 
// Mooduli võtmine, korrutamine ja väärtuse omistamine, x saab väärtuse 9
x = (13 % 5) * 3;
 
// Liitev-omistav operaator, x väärtuseks saab 14
x += 5;
 
// Ühe lahutamise kiirmeetod, x väärtuseks saab 13
x--;

Loogilised

Loogilised tehted on eitus (!), loogiline korrutamine (&&) ja loogiline liitmine (||). Näide tehete kasutamisest:

bool a, b, c;
 
// Algväärtustamine
a = true;
b = false;
 
// Eitus
// c väärtus tuleb väär sest tõest eitati
c = !a;
 
// Loogiline korrutamine
// c väärtuseks tuleb väär, sest üks operandidest on väär
c = a && b;
 
// Loogiline liitmine
// c väärtus tuleb tõene, sest üks operandidest on tõene
c = a || b;

NB! bool andmetüüp on pärit C++ keelest ja C-keeles see tegelikult puudub, sest selle asemel on kasutusel täisarvud, kus 0 tähistab väära ja iga muu arv tõest väärtust. Kuid mugavuse pärast on bool Kodulabori teegis siiski kasutusel ja see on defineeritud kui unsigned char. Konstant true tähistab seal väärtust 1 ja false väärtust 0.

Võrdlused

Arvude väärtuste võrdlemisel saadakse loogilised väärtused. Võrdlustehted on samaväärsus (==), erinevus (!=), suurem (>), suurem-võrdne (> =), väiksem (<) ja väiksem-võrdne (< =). Näide kasutamisest:

int x = 10, y = 1;
 
// Suurem-kui võrdlustehe, mis on tõene
// Tehte ümber on sulud vaid selguse pärast
bool b = (5 > 4);
 
// Erinevuse tehe
// Tehte tulemus on väär
b = (4 != 4);
 
// Aritmeetiline, võrdlus ja loogiline tehe üheskoos
// b tuleb väär, sest esimene loogilise korrutise operand on väär
b = (x + 4 > 15) && (y < 4);

Bititehted

Bititehted on andmetega binaarses arvusüsteemis tegelemiseks. Neid saab rakendada kõigi täisarv-tüüpi andmetega. Bititehted sarnanevad loogiliste tehetega, kuid erinevad selle poolest, et tehe teostatakse iga bitiga eraldi, mitte kogu arvuga. C keeles on bititeheteks inversioon (~), konjunktsioon (&), disjunktsioon (|), antivalentsus (^), nihe vasakule («) ja nihe paremale (»).

// Märgita 8-bitise char-tüüpi muutuja deklareerimine
// Muutuja väärtus on kümnendsüsteemis 5, kahendsüsteemis 101
unsigned char c = 5;
 
// Muutuja c disjunktsioon arvuga 2 (kahendsüsteemis 010)
// c väärtuseks saab 7 (kahendsüsteemis 111)
c = c | 2;
 
// Bitinihe vasakule 2 võrra
// c väärtuseks saab 28 (kahendsüsteemis 11100)
c = c << 2;

Bititehted on hädavajalikud mikrokontrollerite registrite kasutamisel. Täpsemalt tutvustab neid AVR registrite peatükk.

Funktsioonid

Funktsioon on programmilõik, mida saab selle nime järgi täitmiseks välja kutsuda. Funktsioonil võivad olla parameetrid ja funktsioon võib tagastada ühe väärtuse. Kui funktsioon ei tagasta väärtust, on selle tüüp void. Kui funktsioonil pole parameetreid, tuleb vanemat C-keele kompilaatorit kasutades void kirjutada ka parameetrite deklaratsiooni asemele. Näide liitmisfunktsioonist ja tagastamisväärtuseta funktsioonist:

// Kahe int tüüpi parameetriga funktsioon, mis tagastab int-tüüpi väärtuse
int sum(int a, int b) {
	// Kahe arvu liitmine ja summa tagastamine
	return a + b;
}
 
// Ilma parameetrite ja tagastatava väärtuseta funktsioon
void power_off(void) {
}

Funktsiooni kasutamiseks tuleb see välja kutsuda. Funktsioon peab programmikoodis olema deklareeritud enne välja kutsumise kohta. Näide liitmisfunktsiooni väljakutsumisest.

int x;
int y = 3;
 
// Liitmisfunktsiooni väljakutsumine, kus parameetriteks on muutuja ja konstandi väärtus
x = sum(y, 5);
 
// Väljalülitamise funktsiooni väljakutsumine, parameetrid puuduvad
power_off();

C-keele programmi täitmist alustatakse main nimelisest funktsioonist, mis teeb selle kohustuslikuks funktsiooniks.

Laused

Tingimuslause

Tingimuslause võimaldab vastavalt sulgudes oleva avaldise tõesusele täita või mitte täita tingimusele järgnevat lauset või programmilõiku. Tingimuslause võtmesõna on if. Näide kasutamisest:

// Avaldis on tõene ja lause täidetakse,
// sest 2 + 1 on suurem kui 2
if ((2 + 1) > 2) x = 5;
 
// Kui x on 5 ja y on 3, siis täidetakse järgnev programmilõik
if ((x == 5) && (y == 3))
{
	// Suvaline tegevus
	y = 4;
	my_function();
}

Tingimuslause võib olla pikem ja sisaldada ka lauset või programmilõiku, mis täidetakse avaldise mittetõesuse korral. Selleks tuleb if tingimuslause järel kasutada else võtmesõna.

// Kas x on 5 ?
if (x == 5)
{
	// Suvaline tegevus
	z = 3;
}
// Kui x ei olnud 5, kas siis x on 6 ?
else if (x == 6)
{
	// Suvaline tegevus
	q = 3;
}
// Kui x ei olnud 5 ega 6...
else
{
	// Suvaline tegevus
	y = 0;
}

Valikulause

Kui on vaja võrrelda avaldist mitme erineva väärtusega, on mõistlik kasutada valikulauset switch võtmesõnaga. Näide kasutamisest:

int y;
 
// Tingimuslause y võrdlemiseks
switch (y)
{
	// y on 1 ?
	case 1:
		// Suvaline tegevus
		function1();
		break;
 
	// y on 2 ?
	case 2:
		// Suvaline tegevus
		function2();
		break;
 
	// Kõik muud juhtumid
	default:
		// Suvaline tegevus
		functionX();
		// break lauset pole vaja,
		// kuna võrdlemine lõpeb nagunii
}

Tsüklid

Tsüklitega saab programmilõiku täita mitmeid kordi.

while

while võtmesõnaga tähistatud programmilõiku täidetakse seni, kuni sulgudes olev avaldis on tõene

int x = 0;
 
// Tsükkel kestab seni, kuni x on väiksem kui 5
while (x < 5)
{
	// x suurendamine ühe võrra
	x++;
}

for

for võtmesõnaga tsükkel sarnaneb while tsüklile, kuid lisaks on sulgudes ära määratud enne tsüklit täidetav lause ja iga tsükli ajal täidetav lause

Näide:

int i, x = 0;
 
// Algul määratakse i nulliks. Tsüklit täidetaks seni, kuni
// i on vähem kui 5. Iga tsükli lõpus suurendatakse i ühe võrra
for (i = 0; i < 5; i++)
{
	// x suurendamine 2 võrra
	x += 2;
}
 
// Siinkohal tuleb x väärtuseks 10

Tsüklis liikumine

while ja for tsüklitest saab erandkorras väljuda break võtmesõnaga. continue võtmesõnaga saab alustada järgmist tsüklit ilma järgnevat koodi täitmata

int x = 0, y = 0;
 
// Lõputu tsükkel, kuna 1 on loogiline tõesus
while (1)
{    
	// Tsüklist väljutakse, kui x on saavutanud väärtuse 100
	if (x >= 100) break;
 
	// x suurendamine, et tsükkel kunagi lõppeks ka
	x++;
 
	// Kui x on 10 või vähem, siis alustatakse järgmist tsüklit
	if (x <= 10) continue;
 
	// y suurendamine
	y++;
}
 
// Siinkohal on y väärtus 90

Tekstitöötlus

Tekstitöötlusfunktsioone on mikrokontrolleri puhul vaja eelkõige teksti kuvamiseks LCD ekraanile ja selle saatmiseks/vastuvõtmiseks kommunikatsiooniliideste kaudu.

sprintf

sprintf funktsioon toimib sarnaselt C-keeles üldlevinud printf funktsiooniga. Erinevuseks on funktsiooni tulemuse väljastamine puhvrisse (märgimassiivi), mitte standardväljundisse (mis on mikrokontrolleritel enamasti jadaliides, PC peal konsooli aken). Funktsioonil on muutuv arv argumente, mida vormindatakse vastavalt formaadile.

Näide 1:

#include <stdio.h>
 
char buffer[20];
int a = 1, b = 2;
int len = sprintf(buffer, "%d pluss %d on %d", a, b, a + b);
 
// Tulemuseks on tekstistring "1 pluss 2 on 3"

Näiteks kirjutab sprintf funktsioon märgimassiivi buffer teksti, mis on koostatud kolmest argumendist ja on vormindatud vastavalt formaadi tekstistringile. Formaadi tekstistringis tähistab marker (inglise keeles specifier) %d täisarvu tüüpi argumenti, mis tuleb tekstis asendada. Koostatud teksti lõppu lisatakse automaatselt null-bait, mis tähistab tekstistringi lõppu. Kasutaja peab kindlustama, et koostatava teksti ja null-baidi pikkus ei ületaks märgimassiivi pikkust. Sprintf funktsioon lihtsustab fraaside ja lausete koostamist erinevat tüüpi muutujatest. Funktsioon tagastab märgimassiivi salvestatud teksti pikkuse (pikkus ei sisalda null-baiti). Vea korral tagastatakse negatiivne arv.

Näide 2:

#include <stdio.h>
 
char x[20];
sprintf(x, "%s on %d aastat vana", "Juku", 10);
 
// Sama tulemuse saaksime ka konstantselt defineerida:
char x[] = "Juku on 10 aastat vana";

Teise näite formaadi tekstistringis asendatakse marker %s esimese teksti-tüüpi argumendiga ja %d teise täisarv-tüüpi argumendiga. Niipalju, kui on markereid, peab olema ka argumente ning nende tüübid peavad klappima. Samuti peavad argumendid esitatud samas järjekorras nagu markerid. Erinevat tüüpi argumentide jaoks on olemas vastavad formaadi markerid:

Marker Kirjeldus Näide
%c Tähemärk 'a'
%i või %d Täisarv 123
%f Murdarv 3.14f
%s Tekst “näide”
%X Heksadetsimaalarv 0x3F

Standardteegi päisefailides stdio.h, stdlib.h ja string.h on veel terve hulk erinevaid funktsioone erinevate teksti-operatsioonide teostamiseks. Näiteks on võimalik nendega teksti muundada arvudeks, tekste liita ja võrrelda, tekstist märke otsida jpm.

Juhuarvud

Juhuarvude genereerimine ei olegi AVR kontrolleril väga lihtne. Esmalt tuleb juhunumbrigeneraator seemendada arvuga, mille alusel genereeritakse suvaliste numbrite jada. Sama numbri järgi genereeritakse alati sama jada, seega suurema juhuslikkuse saavutamiseks on kasulik seemendus teha arvuga, mis ei ole alati sama - näiteks kasutada selleks kellaaega või lahti ühendatud ADC sisendist väärtust.

Näide, juhuarvu genereerimiseks vahemikus 1 kuni 16 (kaasa arvatud).

#include <stdlib.h>
 
srand(100); // Suvaline seemendusarv
int x = 1 + (rand() % 16);
et/programming/c/crashcourse.txt · Last modified: 2020/07/20 09:00 by 127.0.0.1
CC Attribution-Share Alike 4.0 International
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0