Přeskočit na hlavní obsah

Datové typy

Datový typ říká, jaký druh hodnoty proměnná obsahuje. Program díky tomu ví, kolik paměti má pro hodnotu připravit a jak s ní má zacházet.

Jiný typ se hodí pro celé číslo, jiný pro desetinné číslo, jiný pro text a jiný pro pravda/nepravda.

Běžné typy

V různých jazycích se názvy typů liší, ale myšlenka je podobná.

V C a embedded programech často potkáte tyto typy:

typco znamenápříklad
boollogická hodnota true / falsetrue
charjeden znak nebo malé číslo'A'
intcelé číslo, velikost záleží na platformě42
floatdesetinné číslo s menší přesností3.14f
doubledesetinné číslo, často přesnější než float3.14
uint8_t8bit celé číslo bez znaménka255
int8_t8bit celé číslo se znaménkem-12
uint16_t16bit celé číslo bez znaménka1023
int16_t16bit celé číslo se znaménkem-300
uint32_t32bit celé číslo bez znaménka100000UL
int32_t32bit celé číslo se znaménkem-100000L

Například:

#include <stdbool.h>
#include <stdint.h>

int pocet = 10;
float napeti = 3.3f;
char znak = 'A';
bool hotovo = false;
uint16_t hodnota_adc = 742;

Velikost typu

U malých mikrokontrolérů je důležité, kolik paměti typ zabere. Proto se často používají typy s přesnou velikostí:

uint8_t male_cislo = 255;
int16_t teplota = -12;
uint32_t pocitadlo = 100000;

Význam:

  • uint8_t je celé číslo bez znaménka na 8 bitech,
  • int16_t je celé číslo se znaménkem na 16 bitech,
  • uint32_t je celé číslo bez znaménka na 32 bitech.

Signed a unsigned

U celých čísel je důležité, jestli umí záporné hodnoty.

signed znamená se znaménkem. Takové číslo může být záporné, nulové nebo kladné. Například int8_t umí hodnoty -128127.

unsigned znamená bez znaménka. Takové číslo nemůže být záporné. Všechny bity se použijí jen pro nezápornou hodnotu. Například uint8_t umí hodnoty 0255.

Písmeno u na začátku názvu uint8_t, uint16_t nebo uint32_t znamená právě unsigned. Celý název uint8_t tedy znamená:

unsigned integer, 8 bitů

tedy celé číslo bez znaménka uložené v 8 bitech.

To je užitečné třeba pro:

Když hodnota nikdy nemá být záporná, unsigned typ často dává smysl. Když ale potřebujete ukládat třeba teplotu pod nulou, musíte použít typ se znaménkem, například int16_t.

uint8_t umí hodnoty 0255. Když do něj chcete nacpat 1000, není to větší krabička, jen špatně vybraný typ.

Přesné typy z <stdint.h> jsou v embedded světě velmi užitečné, protože přesně víme, kolik bitů zabírají. U obyčejného int to může záležet na platformě. Na jednom procesoru může mít jinou velikost než na jiném.

Rozsahy čísel

Čím více bitů typ má, tím větší rozsah hodnot umí uložit.

typrozsah
uint8_t0255
int8_t-128127
uint16_t065535
int16_t-3276832767
uint32_t04294967295
int32_t-21474836482147483647

Když měříte desetibitovým ADC, výsledek bývá 01023. Na to stačí uint16_t. Do uint8_t by se taková hodnota nevešla.

Přetečení proměnné

Každý číselný typ má konečný rozsah. Když se pokusíte uložit větší hodnotu, než se do typu vejde, nastane přetečení.

uint8_t pocet = 255;
pocet = pocet + 1;

uint8_t umí nejvýš 255. Po přičtení jedničky tedy nedostanete 256. Hodnota se u běžného 8bitového unsigned typu přetočí zpět na 0.

Tohle je v embedded programování velmi důležité. Počítadlo, časovač nebo index pole může po přetečení najednou vypadat, jako by začal od začátku. Když s tím program nepočítá, chyba se hledá dost nepříjemně.

Převody mezi typy

Hodnotu lze někdy převést z jednoho typu na jiný. Říká se tomu přetypování nebo převod typu.

Někdy je převod bezpečný:

uint8_t male = 200;
uint16_t vetsi = male;

Hodnota 200 se do uint16_t pohodlně vejde, protože uint16_t má větší rozsah.

Jindy se hodnota může ztratit:

uint16_t velke = 1000;
uint8_t male = velke;

uint8_t neumí uložit 1000. Výsledek tedy nebude 1000. Program sice může projít překladem, ale hodnota už nebude ta, kterou jste čekali.

Převod desetinného čísla na celé číslo zahodí desetinnou část:

float napeti = 3.8f;
int cele = (int)napeti;

Proměnná cele bude mít hodnotu 3. Ne 4. Počítač nezaokrouhlil, jen uřízl část za desetinnou tečkou.

Převod není kouzlo

Přetypování neznamená, že se hodnota vždy správně vejde. Znamená jen: "Chci, aby se na tuto hodnotu program díval jako na jiný typ." Když je nový typ příliš malý, část informace se může ztratit.

Proč na tom záleží

Na počítači si často můžete dovolit plýtvat pamětí. Na malém čipu ne. Když má mikrokontrolér jen pár kilobajtů RAM, je rozdíl, jestli jedna hodnota zabere 1 byte, nebo 4 byty.

Zároveň typ chrání program před nesmysly. Když má proměnná vyjadřovat, jestli LED svítí, dává smysl použít logickou hodnotu:

bool led_sviti = true;

Ne číslo, u kterého později nikdo neví, jestli 2 znamená zapnuto, vypnuto, nebo "někdo to kdysi napsal a odešel".