70
Procedurálne programovanie: 9. prednáška Gabriela Kosková

Procedur álne programovanie: 9 . prednáška

  • Upload
    maude

  • View
    87

  • Download
    3

Embed Size (px)

DESCRIPTION

Procedur álne programovanie: 9 . prednáška. Gabriela Kosková. Obsah. príklady k štruktúram a ukazovateľom (2) oddelen ý preklad b itov é operácie a polia. Príklad: simulácia pokladní v obchode. N pokladní v obchode Pri každej pokladni – rad zákazníkov. ZAKAZNIK *pokladne[N];. - PowerPoint PPT Presentation

Citation preview

Page 1: Procedur álne programovanie: 9 . prednáška

Procedurálne programovanie:9. prednáška

Gabriela Kosková

Page 2: Procedur álne programovanie: 9 . prednáška

Obsah

• príklady k štruktúram a ukazovateľom (2)

• oddelený preklad

• bitové operácie a polia

Page 3: Procedur álne programovanie: 9 . prednáška

Príklad: simulácia pokladní v obchode

• N pokladní v obchode

• Pri každej pokladni – rad zákazníkov

typedef struct zakaznik { int cislo; struct zakaznik *dalsi;} ZAKAZNIK;

ZAKAZNIK *pokladne[N];

• funkcie:– Výpis všetkých zákazníkov– Pridanie zákazníka– Vybavenie zákazníka (ten odíde)

Page 4: Procedur álne programovanie: 9 . prednáška

Príklad: simulácia pokladní v obchode

void vypis_vsetkych_zakaznikov(ZAKAZNIK *pokladne[N]);void pridaj_zakaznika(ZAKAZNIK *pokladne[N]);ZAKAZNIK *vyrob_zakaznika(int z);int najkratsi_rad(ZAKAZNIK *pokladne[N]);void vybaveny_zakaznik(int p, ZAKAZNIK *pokladne[N]);

void odchod_zakaznika(int cislo, ZAKAZNIK *pokladne[N]);int main();

• Námety na zamyslenie

• Uzatvorenie pokladne (potrebné zmeny aj v iných funkciách)

Page 5: Procedur álne programovanie: 9 . prednáška

void vypis_vsetkych_zakaznikov(ZAKAZNIK *pokladne[N]) { int i; ZAKAZNIK *akt; for(i=0; i<N; i++) { akt = pokladne[i]; printf("Pokladna %d: ", i); while(akt != NULL) { printf("%d ", akt->cislo); akt = akt->dalsi; } printf("\n"); }}

ZAKAZNIK *vyrob_zakaznika(int z) { ZAKAZNIK *zak = (ZAKAZNIK *) malloc(sizeof(ZAKAZNIK)); zak->cislo = z; zak->dalsi = NULL; return zak;}

Page 6: Procedur álne programovanie: 9 . prednáška

void pridaj_zakaznika(ZAKAZNIK *pokladne[N], int z) {

int min = najkratsi_rad(pokladne); ZAKAZNIK *akt = pokladne[min]; if(akt == NULL) pokladne[min] = vyrob_zakaznika(z); else { akt = pokladne[min]; while(akt->dalsi != NULL) akt = akt->dalsi; akt->dalsi = vyrob_zakaznika(z); } }

Page 7: Procedur álne programovanie: 9 . prednáška

int najkratsi_rad(ZAKAZNIK *pokladne[N]) { int min_dlzka, najkratsi, i, dlzka; ZAKAZNIK *akt; for(i=0; i<N; i++) { dlzka = 0; akt = pokladne[i]; while(akt != NULL) { dlzka++; akt = akt->dalsi; } if(i==0 || dlzka < min_dlzka) { min_dlzka = dlzka; najkratsi = i; } } return najkratsi; }

Page 8: Procedur álne programovanie: 9 . prednáška

void vybaveny_zakaznik(int p, ZAKAZNIK *pokladne[N]) { ZAKAZNIK *zrus;

if(pokladne[p] != NULL) { printf("Vybaveny zakaznik c. %d\n", pokladne[p]->cislo); zrus = pokladne[p]; pokladne[p] = pokladne[p]->dalsi; free(zrus); } }

Page 9: Procedur álne programovanie: 9 . prednáška

Rodostrom• Záznam o človeku:

– Meno– Priezvisko– Ukazovateľ na záznam o matke– Ukazovateľ na záznam o otcovi– Počet detí– Pole ukazovateľov na záznamy o ďeťoch

typedef struct clovek { char meno[20]; char priezvisko[20]; struct clovek *matka; struct clovek *otec; int pocet_deti; struct clovek **deti;} CLOVEK;

Page 10: Procedur álne programovanie: 9 . prednáška

CLOVEK **tety_a_strykovia(CLOVEK *clovek) { int pocet, i, j; CLOVEK **tetystr; pocet = clovek->matka->matka->pocet_deti -1; pocet += clovek->otec->matka->pocet_deti -1; tetystr = (CLOVEK **) malloc(pocet * sizeof(CLOVEK *)); j = 0; for(i=0; i<clovek->matka->matka->pocet_deti; i++) if(clovek->matka->matka->deti[i] != clovek->matka) { tetystr[j] = clovek->matka->matka->deti[i]; j++; } for(i=0; i<clovek->otec->matka->pocet_deti; i++) if(clovek->otec->matka->deti[i] != clovek->otec) { tetystr[j] = clovek->otec->matka->deti[i]; j++; } return tetystr; }

Page 11: Procedur álne programovanie: 9 . prednáška

Rodostrom• Skúste premyslieť

– Nájdenie všetkých bratrancov a sesterníc– Čo ak pripustíme aj nevlastných súrodencov (treba kontroľovať aj cez otca aj

matku)

Page 12: Procedur álne programovanie: 9 . prednáška

Procedurálne programovanie: Oddelený preklad

Page 13: Procedur álne programovanie: 9 . prednáška

Oddelený preklad

• vkladanie súborov – #include vznikne jeden .OBJ súbor

• oddelený preklad– každý súbor sa preloží zvlášť (vznikne viac .OBJ súborov) a potom

sa spoja pomocou linkeru

Page 14: Procedur álne programovanie: 9 . prednáška

Príklad oddeleného prekladu

s2.cs1.c s3.c s1.c s2.c s3.c

s.c

#include "s1.c"

#include "s2.c"

#include "s3.c"

s.obj

s1.obj s2.obj s3.obj

link s link s1, s2, s3

vkladanie súborov: oddelený preklad:

Page 15: Procedur álne programovanie: 9 . prednáška

Oblasť platnosti identifikátorov

• jazyk C umožňuje rôzne spôsoby ako stanoviť kde, kedy a aký identifikátor bude komu dostupný:– globálne a lokálne premenné

– pamäťové triedy

– typové modifikátory

Page 16: Procedur álne programovanie: 9 . prednáška

Globálne premenné

• organizácia v programe: globálne definície a deklarácie

definície funkcií

globálne definície: definujú premenné, rozsah ich platnosti: od miesta definície po koniec súboru (nie programu - program sa môže skladať z viac súborov)

globálne deklarácie: deklarácie premenných, ktoré sú definované v inom súbore. často sú špecifikované slovom extern - externé deklarácie

Page 17: Procedur álne programovanie: 9 . prednáška

Príklad: globálne definície

int i;

void prva(){...}

int j;

int druha(){...}

char *tretia(){...}

premenná i je platná pre všetky 3 funkcie

premenná j je platná len pre funkcie:druha() a tretia()

Page 18: Procedur álne programovanie: 9 . prednáška

Lokálne premenné

• definované vo funkciách

• platnosť lokálnych premenných: od definície po koniec funkcie

int i1, i2;

void prva() {int i1, j1;...}

int j1, j2;

int druha(){int i1, j1, k1;...}

globálna premenná i1 je prekrytá lokálnou premennou i1 (používať sa môžu premenné: i1, j1 (lokálne) a i2 (globálna))

dve globálne premenné: i2, j2 a tri lokálne premenné: i1, j1, k1.

Page 19: Procedur álne programovanie: 9 . prednáška

Inicializácia lokálnych a globálnych premenných

• lokálne premenné:– nie sú automaticky inicializované

• globálne premenné:– automaticky inicializované na 0 (0.0, \0)

(lepšie - nespoliehať sa na to)

Page 20: Procedur álne programovanie: 9 . prednáška

Pamäťové triedy

• určujú v ktorej časti pamäte bude premenná umiestnená a kde bude viditeľná– auto– extern– static– register

Page 21: Procedur álne programovanie: 9 . prednáška

Trieda auto

• automatické premenné– implicitne pre lokálne premenné

– uložená v zásobníku (stacku)

– existuje od vstupu do funkcie do jej konca

– nie je inicializovaná

void func(){ auto int i; auto int j = 5;}

je ekvivalentné

void func(){ int i; int j = 5;}

Page 22: Procedur álne programovanie: 9 . prednáška

Trieda extern

• implicitne pre globálne premenné

• uložená v dátovej oblasti

• používa sa pri oddelenom preklade súborov, kde viac súborov zdiela jednu premennú– v jednom súbore je táto premenná definovaná bez kľúčového slova extern, v ostatných súboroch musí byť použité extern

int suma;

v súbore s1.c

definícia

extern int suma;

v súbore s2.c

deklarácia

Page 23: Procedur álne programovanie: 9 . prednáška

Trieda static

• neexistuje žiadna implicitná definícia

• najčastejšie lokálne premenné (definované vo funkcii), ktoré si nechávajú svoju hodnotu medzi jednotlivými volaniami funkcie

• premenná existuje od prvého volania funkcie do konca programu

int f() { int x = 2; static int i = 0; printf("i: %d, x: %d \n", i, x); i++; x++;}

for(j = 0; j < 3; j++) f();

i: 0, x: 2i: 1, x: 2i: 2, x: 2

Page 24: Procedur álne programovanie: 9 . prednáška

Trieda static

• globálne premenné: tiež static - viditeľné len v module, kde sú definované

• ak viac static premenných, radšej každú na zvlášť riadku

static int i, j; static int i;static int j;

Page 25: Procedur álne programovanie: 9 . prednáška

Trieda register

• jazyk C - nízkoúrovňový a preto umožňuje, aby premenná bola zapísaná v registri– ak sa dá

– do ktorého registra - vyberá si prekladač

– len lokálne premenné

– tie, ku ktorým je vhodné pristupovať rýchlo

register int i;

register int i;register int j;

ak je viac premenných, označenie triedy register vyznačiť pre každú premennú zvlášť

Page 26: Procedur álne programovanie: 9 . prednáška

Prílad použitia triedy register

void nasobilka(register int k){ register int i;

for (i = 1; i <= 10; i++) printf("%2d x %2d = %2d \n", i, k, i * k);}

násobky čísla k

Page 27: Procedur álne programovanie: 9 . prednáška

Typové modifikátory

• ľubovoľná premenná nejakého dátového typu (int i) zaradená do nejakej pamäťovej triedy (napr. static) môže byť modifikovaná typovým modifikátorom:– const– volatile

static const unsigned int j = 5;

napríklad:

Page 28: Procedur álne programovanie: 9 . prednáška

Modifikátor const

• v ANSI C

• po inicializácii už nemôže byť menená hodnota premennej

• podobne ako konštanta (#define), len má určený typ, čo konštanta nemá (dá sa využiť ku kontrolám prekladača (napr. typ skutočných parametrov funkcie))

• najčastejšie: pri definícii formálnych parametrov funkcie - parameter označený ako const je len vstupným parametrom (vo funkcii sa nemení)

int hladaj(const char *str, char co)

napríklad:

Page 29: Procedur álne programovanie: 9 . prednáška

Modifikátor const

const float pi = 3.14159;const int max = 100;

int pole[max];

pi = 3.14;

• časté chyby:

chyba: pi sa už nedá meniť

chyba: max nie je konštanta

Page 30: Procedur álne programovanie: 9 . prednáška

Modifikátor volatile

• v ANSI C

• málo časté

• upozorňuje prekladač, že premenná môže byť modifikovaná nejakou bližšie nešpecifikovanou asynchrónnou udalosťou (napr. pomocou prerušenia)– napr. cyklus (neobsahujúci premennú pocet), ktorý je závislý na

premennej pocet a tá je menená hardverovým prerušením

– ak by nebola označená modifikátorom volatile - prekladač by to mohol optimalizovať tak, že by premennú pocet nahradil jej hodnotou, akú mala pred cyklom

Page 31: Procedur álne programovanie: 9 . prednáška

Príklad: modifikátor volatile

volatile int pocet;

void wait(int maximum) { pocet = 0; while (pocet < maximum) ;}

cyklus skončí po zmene premennej pocet nejakým hardverovým prerušením

Page 32: Procedur álne programovanie: 9 . prednáška

Bloky

• blok programu - uzatvorený v { } môže obsahovať definície premenných– lokálne premenné (auto, alebo static)

– viditeľné sú len v bloku

if (i > 0) { int i; ...}else { double f; ...}

Page 33: Procedur álne programovanie: 9 . prednáška

Príklad oddeleného prekladu

s2.cs1.c s3.c s1.c s2.c s3.c

s.c

#include "s1.c"

#include "s2.c"

#include "s3.c"

s.obj

s1.obj s2.obj s3.obj

link s link s1, s2, s3

vkladanie súborov: oddelený preklad:

Page 34: Procedur álne programovanie: 9 . prednáška

Oblasť platnosti identifikátorov: zhrnutie

• globálne a lokálne premenné

• pamäťové triedy: – auto (implicitne lokálne premenné, v stacku)– extern (implicitne globálne premenné, v dátovej oblasti)– static (lokálne premenné: zachovávajú hodnotu medzi volaniami

funkie, globálne premenné: platnosť v rámci jedného súboru)– register (lokálne premenné, zapísané v registri)

• typové modifikátory:– const (konštantné premenné, nemenia hodnotu)– volatile (lokálne premenné, zmena hardverovým prerušením)

Page 35: Procedur álne programovanie: 9 . prednáška

Oddelený preklad súborov

• rozdeliť program na viac čo najmenej závislých častí• definovať rozhranie - spôsob komunikácie medzi

oddelenými časťami (.h súbory)– pomocou funkcií (lepšie ako pomocou globálnych premenných

viditeľných vo všetkých súboroch)

Page 36: Procedur álne programovanie: 9 . prednáška

Rozšírenie platnosti globálnej premennej

• globálna premenná:– definovaná v jednom súbore– deklarovaná pomocou extern v ostatných súboroch

Page 37: Procedur álne programovanie: 9 . prednáška

Príklad: rozšírenie platnosti globálnej premennej

int x;extern double f;

int fun(void) { return (x + (int) f);}

#include <stdio.h>

extern int x;extern int fun(void);

double f;

void main(){ x = 3; f = 3.5; printf("%d \n", fun());}

A.c: B.c:

definície

deklarácie

Page 38: Procedur álne programovanie: 9 . prednáška

Statické globálne premenné a funkcie

• trieda static - viditeľné len v module, v ktorom boli definované– pre globálne premenné

– pre funkcie

Page 39: Procedur álne programovanie: 9 . prednáška

Príklad: statické globálne premenné a funkcie

static int x;extern double f;

static int fun(void) { return x;}static int funkcia(void) { return (x + (int) f);}

#include <stdio.h>

extern int x;extern int funkcia(void);double f;

static void fun(void) { prinftf("%d \n", funkcia());}

void main() { x = 3; f = 3.5; printf("%d \n", fun());}

A.c: B.c:

pri linkovaní chyba:x: v A.c static v B.c len deklarácia

Page 40: Procedur álne programovanie: 9 . prednáška

Zdrojové a hlavičkové súbory

• .c súbory - definície globálnych premenných a funkcií:– pre všetky moduly (žiadne označenie)

– len pre aktuálny modul (označenie static)

• .h súbory - definujú rozhranie, t.j. definujú globálne premenné a funkcie, ktoré sa používajú v iných moduloch (označenie extern)

• .c súbory include-ujú len .h súbory ktoré potrebujú (nikdy ne-include-ujú .c súbory)

Page 41: Procedur álne programovanie: 9 . prednáška

Ako udržať poriadok vo veľkom programe

1. definície funkcií a premenných v súbore program_1.c

2. v program_1.c - striktne rozlíšené, čo sa bude používať v rámci súboru a čo mimo neho (čo najmenej)

3. všetky ostatné globálne premenné a funkcie označiť static

4. funkčné prototypy zdielaných funkcií a premenných - do program_1.h, označíme ich extern

5. ak poskytujeme aj symbolické konštanty - dáme ich len do program_1.h

6. program_1.c začína: #include <stdio.h>#include "program_1.h"

Page 42: Procedur álne programovanie: 9 . prednáška

Ako udržať poriadok vo veľkom programe

7. súbor program_2.c obsahujúci ďalší modul programu a využíva premenné, funkcie alebo konštanty z modulu program_1, začína:

#include <stdio.h>#include "program_1.h"#include "program_2.h"

Page 43: Procedur álne programovanie: 9 . prednáška

Odporučený obsah .c súborov

1. dokumentačná časť

(meno súboru, verzie, stručný popis modulu, meno autora a dátum)

2. všetky potrebné #include len súbory .h, nie .c!

najprv systémové < > a potom vlastné " "

3. deklarácie importovaných objektov (extern)len ak nie sú v .h súbore spolupracujúceho modulu (čomu dávame prednosť) - v iných moduloch sú tieto objetky bez špecifikovanej triedy

4. definície globálnych premenných

premenné definované mimo funkcií zdielané inými modulmi (čo najmenej!)

Page 44: Procedur álne programovanie: 9 . prednáška

Odporučený obsah .c súborov

5. lokálne #definedefinícia konštánt a makier len pre aktuálny modul

len ak veľmi rozsiahle - do zvlášť .h

6. definície lokálnych typovtypedef len pre aktuálny modul

len ak veľmi rozsiahle - do zvlášť .h

7. definície premenných len pre aktuálny modulglobálne len pre aktuálny modul - static

8. úplné funkčné prototypy funkcií len pre aktuálny modul

9. funkcia main()

10. definície funkcií aj pre iné moduly

11. definície funkcií len pre aktuálny modul

Page 45: Procedur álne programovanie: 9 . prednáška

Odporučený obsah .h súborov

1. dokumentačná časť(meno súboru, verzie, stručný popis modulu, meno autora a dátum)

2. definície symbolických konštánt ktoré sa budú používať aj v iných moduloch

3. definície makier s parametrami, ktoré sa budú používať aj v iných moduloch

4. definície typov, ktoré sa budú používať aj v iných moduloch

5. deklarácie premenných aktuálneho modulu, ktoré sa budú používať v iných moduloch (tu označené extern)

6. funkčné prototypy funkcií aktuálneho modulu, ktoré sa budú používať v iných moduloch (tu označené extern)

Page 46: Procedur álne programovanie: 9 . prednáška

Príklad: oddelený preklad

globálne premenné a funkcie

lokálne premenné a funkcie

kruh_main double obvod

double

vyp_priemer(double

polomer)

double polomer, obsahvoid vyp_obsah(double polomer)doble vyp_obvod()void vypocet(void)

kruh_io double vstup_dat()double vystup_dat(double obsah)

double polomer

• program na výpočet obsahu a obvodu kruhu:

kruh_main.c, kruh_main.h, kruh_io.c, kruh_io.h

premenné a funkcie definované v jednom z modulov - môžu sa používať aj v rámci druhého modulu

Page 47: Procedur álne programovanie: 9 . prednáška

#include <stdio.h>#include "kruh_main.h"#include "kruh_io.h"

double obvod;#define pi 3.14;

static double polomer;static double obsah;

double vyp_priemer(double polomer);static void vyp_obsah (double polomer);static doble vyp_obvod();static void vypocet(void);

void main() { polomer = vstup_dat(); if (polomer == CHYBA_DAT) printf("Chybny polomer."); else { vypocet(); vystup_dat(obsah); }}

static void vyp_obsah(double polomer) { obsah = PI * polomer *polomer;}

static doble vyp_obvod() { return(PI*vyp_priemer(polomer));}

static void vypocet(void) { obvod = vyp_obvod(); vyp_obsah(polomer);}

double vyp_priemer(double polomer) { return (2 * polomer);}

kruh_main.cglob. definície

Page 48: Procedur álne programovanie: 9 . prednáška

extern double obvod;

extern double vyp_priemer(double polomer);

kruh_main.h

Hlavičkový súbor modulu kruh_main

deklarácie premenných a funkcií aktuálneho modulu, ktoré sa budú používať v iných moduloch (tu označené extern)

Page 49: Procedur álne programovanie: 9 . prednáška

#include <stdio.h>#include "kruh_io.h"#include "kruh_main.h"

#define kontrola(x) ((x >= 0.0) ? x : CHYBA_DAT)

static double polomer;

double vstup_dat(void) { printf("Zadaj polomer kruznice: "); scanf("%lf", &polomer); return kontrola(polomer);}

void vystup_dat(double obsah) { double priemer;

printf("Obsah kruhu s polomerom %6.2f je %.2f\n", polomer, obsah); priemer = vyp_priemer(polomer); printf("Obvod kruhu s polomerom %6.2f je %.2f\n", polomer, obvod);}

glob. definície

kruh_io.c

Page 50: Procedur álne programovanie: 9 . prednáška

#define CHYBA_DAT -1

extern double vstup_dat();

extern double vystup_dat(double obsah);

Hlavičkový súbor modulu kruh_io

deklarácie premenných a funkcií aktuálneho modulu, ktoré sa budú používať v iných moduloch (tu označené extern)

kruh_io.h

Page 51: Procedur álne programovanie: 9 . prednáška

#include <stdio.h>

#include "kruh_io.h"#include "kruh_main.h"

#define kontrola(x) ((x >= 0.0) ? x : CHYBA_DAT)

static double polomer;

double vstup_dat(void) { printf("Zadaj polomer kruznice: "); scanf("%lf", &polomer); return kontrola(polomer);}

void vystup_dat(double obsah) { double priemer;

printf("Obsah kruhu s polomerom %6.2f je %.2f\n", polomer, obsah); priemer = vyp_priemer(polomer); printf("Obvod kruhu s polomerom %6.2f je %.2f\n", polomer, obvod);}

kruh_io.c

static void vyp_obsah(double polomer) { obsah = PI * polomer *polomer;}

static doble vyp_obvod() { return(PI*vyp_priemer(polomer));}

static void vypocet(void) { obvod = vyp_obvod(); vyp_obsah(polomer);}

double vyp_priemer(double polomer) { return (2 * polomer);}

#include <stdio.h>

#include "kruh_main.h"#include "kruh_io.h"

double obvod;#define pi 3.14;

static double polomer;static double obsah;

static void vyp_obsah (double polomer);static doble vyp_obvod();static void vypocet(void);

void main() { polomer = vstup_dat(); if (polomer == CHYBA_DAT) printf("Chybny polomer."); else { vypocet(); vystup_dat(obsah); }} kruh_main.c

extern double obvod;

extern double vyp_priemer(double polomer);

kruh_main.h

#define CHYBA_DAT -1

extern double vstup_dat();

extern double vystup_dat(double obsah); kruh_io.c

Oddelený preklad

Page 52: Procedur álne programovanie: 9 . prednáška

Visual C++ a oddelený preklad

• vytvorenie projektu

(Win32 Console Application)

• vloženie súboru– C++ Source File

– C/C++ Header File

• Menu Build1. Build program.exe

2. Compile program.exe

Page 53: Procedur álne programovanie: 9 . prednáška

Procedurálne programovanie:Bitové operácie

Page 54: Procedur álne programovanie: 9 . prednáška

Práca s bitmi

• práca s reprezentáciou čísla v dvojkovej sústave

• Príklady:– 1: 001– 2: 010– 3: 011– 4: 100

Prevod čísla do dvojkovej sústavy -

príklad prevod čísla 4:

4 / 2 = 2 zvyšok 0

2 / 2 = 1 zvyšok 0

1 / 2 = 0 zvyšok 1

Prevod čísla do dvojkovej sústavy (delenie dvomi)

Výsledok sa použije ako delenec v nasledujúcej časti

prevodu

Zvyšky prečítané zospodu hore

predstavujú číslo v dvojkovej sústave

Page 55: Procedur álne programovanie: 9 . prednáška

Oprácie s jednotlivými bitmi

• operátory:– & - bitový súčin (AND)– | - bitový súčet (OR)– ^ - bitový exkluzívny súčet (XOR)– << - posun doľava– >> - posun doprava– ~ - jednotkový doplnok (negácia bit po bite)

• argumenty nemôžu byť float, double ani long double

Page 56: Procedur álne programovanie: 9 . prednáška

Bitový súčin

• i-ty bit výsledku x & y bude 1 vtedy, ak i-ty bit x aj i-ty bit y sú 1, inak 0 (AND po bitoch)

#define je_neparne(x) (1 & (unsigned) (x))

0000 0000 0000 0001xxxx xxxx xxxx xxx?&

0000 0000 0000 000?0

01

1

• ak chceme premennú typu int použiť ako ASCII znak, teda potrebujeme najmenších 7 bitov

0000 0000 0111 1111 = 0x7F c &= 0x7F;c = c & 0x7F;

x y x&y0 0 00 1 01 0 01 1 1

Page 57: Procedur álne programovanie: 9 . prednáška

Rozdiel medzi bitovým a logickým súčin

• k: 1, pretože 1 a 2 sú kladné číla, teda majú logickú hodnotu true (pravda) a && je logický súčin

unsigned int i = 1, j = 2, k, l;k = i && j;l = i & j;

• l: 0, pretože 1 = 0000 0001

2 = 0000 0010

a & je bitový súčin

Page 58: Procedur álne programovanie: 9 . prednáška

Bitový súčet

• i-ty bit výsledku x | y bude 1 vtedy, ak i-ty bit x alebo i-ty bit y sú 1, inak 0 (OR po bitoch)

• používa sa na nastavenie niektorých bitov na jednotku, pričom nechá ostatné bity nezmenené

#define na_neparne(x) (1 | (unsigned) (x))

0000 0000 0000 0001xxxx xxxx xxxx xxx?|

xxxx xxxx xxxx xxx?1

01

1

makro vráti nepárne číslo nezmenené a párne zväčší o 1

x y x|y0 0 00 1 11 0 11 1 1

Page 59: Procedur álne programovanie: 9 . prednáška

Bitový exkluzívny súčet

• i-ty bit výsledku x ^ y bude 1 vtedy, ak sa i-ty bit x nerovná i-temu bitu y, inak 0 (XOR po bitoch)

if (x ^ y) /* cisla sú rozdielne */

x y x^y0 0 00 1 11 0 11 1 0

Page 60: Procedur álne programovanie: 9 . prednáška

Bitový posun doľava

• x << n posunie bity v x o n pozícií doľava

• bity zľava sa strácajú bity zprava sú dopĺňané nulami

x = x << 1;

x = 0001 1011 0010 0101

x << 1 = 0011 0110 0100 1010

= 6949

= 13898 = 2 * 6949

na rýchle násobenie dvomi

x = x << 3; vynásobesnie 23 = 8

Page 61: Procedur álne programovanie: 9 . prednáška

Bitový posun doprava

• x >> n posunie bity v x o n pozícií doprava

• bity zprava sa strácajú bity zľava sú dopĺňané nulami

x = x >> 1;

x = 0011 0110 0100 1010

x >> 1 = 0001 1011 0010 0101

= 13898

= 6949 = 13898 / 2

na rýchle celočíselné delenie dvomi

x = x >> 3; celočíselné delenie 23 = 8

Page 62: Procedur álne programovanie: 9 . prednáška

Príklad: delenie a násobenie

• bitové posuny sú rýchlejšie ako násobenie a delenie násobkami dvojky

i = j * 80;i = (j << 6) + (j << 4);

80 = 64 + 16 rýchlejšie

Page 63: Procedur álne programovanie: 9 . prednáška

0000 0000 1100 10011

Príklad: zistenie hodnoty konkrétneho bitu

#define ERROR -1#define CLEAR 1#define BIT_V_CHAR 8

int bit(unsigned x, unsigned i){ if (i >= sizeof(x) * BIT_V_CHAR) return (ERROR); else return ((x >> i) & CLEAR);}

0011 0010 0101 00101

0001 1001 0010 10011

0000 1100 1001 01001

0000 0110 0100 10101

0000 0011 0010 01011

0000 0001 1001 00101

0000 0000 1100 10011

& 0000 0000 0000 0001

0000 0000 0000 0001

vráti hodnotu i-teho bitu x

Page 64: Procedur álne programovanie: 9 . prednáška

Negácia po bitoch

• jednotkový doplnok ~x• prevráti nulové bity na jednotkové a naopak

• Použitie napr. ak sa chceme vyhnúť na počítači závislej dĺžke celého čísla:

x &= 0xFFF0;

x &= ~0xF;

nastavenie posledných 4 bitov na nulu - len ak platí

sizeof(int) == 2

nastavenie posledných 4 bitov na nulu - platí pre všade

Page 65: Procedur álne programovanie: 9 . prednáška

Príklad

#include <stdio.h>

int dlzka_int(){ unsigned int x, i = 0; x = ~0; /* negácia 0 -> same 1 */

while ((x >> 1) != 0) i++; return (++i);}

int main(){ printf("Dlzka typu int je %d bitov\n", dlzka_int()); return 0;}

Zistenie dĺžkyky typu int v bitoch

Page 66: Procedur álne programovanie: 9 . prednáška

Práca so skupinou bitov

#define READ 0x8#define WRITE 0x10#define DELETE 0x20

unsigned int stav;

stav |= READ | WRITE | DELETE;stav |= READ | WRITE;stav &= ~(READ | WRITE | DELETE);stav & = ~READ;if ( ! (stav & (WRITE | DELETE))) ...

• stavová premenná stav - definuje práva na prístup k súboru

READ: 23 = 0000 0100 WRITE: 24 = 0000 1000 DELETE: 25 = 0001 0000

nastaví 2., 3. a 4. bit na 1

nastaví 2., 3. bit na 1

nastaví 2., 3. a 4. bit na 0

nastaví 2. bit na 0

ak 2. a 3. bit sú nulové

Page 67: Procedur álne programovanie: 9 . prednáška

Bitové pole

• štruktúra, ktorej veľkosť je obmedzená veľkosťou typu int

• najmenšia dĺžka položky je 1 bit• definuje podobne ako štruktúra, ale každá položka

bitového poľa je určená menom a dĺžkou v bitoch• môže byť signed aj unsigned (preto vždy uviesť)• oblasti použitia:

– uloženie viac celých čísel v jednom (šetrenie pamäte)

– pre prístup k jednotlivým bitom (často)

Page 68: Procedur álne programovanie: 9 . prednáška

Príklad bitového poľa

typedef struct { unsigned den : 5; unsigned mesiac : 4; unsigned rok : 7;} DATUM;

DATUM dnes, zajtra;dnes.den = 29;dnes.mesiac = 11;dnes.rok = 2012 - 1980;zajtra.den = dnes.den + 1;

• uloženie dátumu do jednotho int-u:– deň - najmenších 5 bitov,

– mesiac - ďalšie 4 bity,

– rok - zvyšných 7 bitov (max. 127, preto rok - 1980)

bity 0-4

bity 5-8

bity 9-15

Page 69: Procedur álne programovanie: 9 . prednáška

Príklad bitového poľa

#include <stdio.h>

typedef struct { unsigned den : 5; /* bity 0 - 4 */ unsigned mesiac : 4; /* bity 5 - 8 */ unsigned rok : 7; /* bity 9 - 15 */} DATUM;

typedef union { DATUM datum; unsigned int cislo;} BITY;

Dátum ako bitové pole aj hexadecimálne číslo (union)

Page 70: Procedur álne programovanie: 9 . prednáška

Príklad bitového poľa - pokračovanie

int main(void){ BITY dnes; int d, m, r;

printf("Zadaj dnesny datum [dd mm rrrr]: "); scanf("%d %d %d", &d, &m, &r); dnes.datum.den = d; dnes.datum.mesiac = m; dnes.datum.rok = r - 1980;

printf("datum: %2d.%2d.%4d - cislo: %X hexa\n", dnes.datum.den, dnes.datum.mesiac, dnes.datum.rok + 1980, dnes.cislo); return 0;}

#include <stdio.h>

typedef struct { unsigned den : 5; unsigned mesiac : 4; unsigned rok : 7;} DATUM;

typedef union { DATUM datum; unsigned int cislo;} BITY;