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:
| typ | co znamená | příklad |
|---|---|---|
bool | logická hodnota true / false | true |
char | jeden znak nebo malé číslo | 'A' |
int | celé číslo, velikost záleží na platformě | 42 |
float | desetinné číslo s menší přesností | 3.14f |
double | desetinné číslo, často přesnější než float | 3.14 |
uint8_t | 8bit celé číslo bez znaménka | 255 |
int8_t | 8bit celé číslo se znaménkem | -12 |
uint16_t | 16bit celé číslo bez znaménka | 1023 |
int16_t | 16bit celé číslo se znaménkem | -300 |
uint32_t | 32bit celé číslo bez znaménka | 100000UL |
int32_t | 32bit 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_tje celé číslo bez znaménka na 8 bitech,int16_tje celé číslo se znaménkem na 16 bitech,uint32_tje 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 -128 až 127.
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 0 až 255.
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:
- hodnotu z ADC,
- počítadlo,
- bitové masky,
- registry,
- délku zprávy,
- počet prvků v poli.
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 0 až 255.
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.
| typ | rozsah |
|---|---|
uint8_t | 0 až 255 |
int8_t | -128 až 127 |
uint16_t | 0 až 65535 |
int16_t | -32768 až 32767 |
uint32_t | 0 až 4294967295 |
int32_t | -2147483648 až 2147483647 |
Když měříte desetibitovým ADC,
výsledek bývá 0 až 1023.
Na to stačí uint16_t.
Do uint8_t by se taková hodnota nevešla.
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ř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".