FULL-C: 64 bit

Tato stránka popisuje programovací jazyk FULL-C, který je dostupný na vybraných zařízeních SDS. 
Některá zařízení používají SDS-C, pro který máme návody jinde na této WiKi.

FULL-C a podpora 64 bitových čísel

Nová verze FULL-C pracuje nejen s 32bit čísly (int, long, nebo menší), ale také s 64bit čísly.

Použití 64bit je nezbytné v řadě úkolů, např. počítadla impulsů, nebo při provádění výpočtů, kdy mezivýsledky jsou větší než co by se do 32bit čísel vlezlo.

64bit čísla lze také výhodně využít pro fixed-point aritmetiku, pokud nám nestačí přesnost typu float (32bit), který SDS nabízí.

Pozor, počítání s 64bit čísly je jemně (nezřetelně, ale přece) pomalejší než nativní použití 32bit čísel či floatu, ale to je nakonec jen nepodstatné upozornění. A samozřejmě zaberou 8 bajtů paměti, oproti 4 bajtům pro 32bit čísla. Ale to je jasné a to nakonec chceme.



Detaily

Deklarace je možná pouze pomocí uint64_t nebo int64_t :

// 64bit bez znaménka
uint64_t u64;

// 64bit se znaménkem
int64_t i64;


Tisknutí lze provádět pomocí sprintf/snprintf/printf.

Vždy musíte správně použít "u" nebo "d" podle znaménka (unsigned nebo signed), a současně vždy uvést modifikátor délky "ll" (64-bit). Tedy "%lld" pro tisk typu int64_t.

Takže:

uint64_t hodnota64;

hodnota64 = 1234;

printf("hodnota je %llu \n", hodnota64);

nebo

int64_t hodnota64sig;

hodnota64sig = -1234;

printf("hodnota je %lld \n", hodnota64sig);

Všimněte si, že jsme použili buď %lld nebo %llu, právě přesně podle toho, jestli je to int64_t nebo uint64_t.

Ještě lze použít %x pro hexa výpis (ten vypíše všech 64bitů tak jak jsou fyzicky v paměti, tady se na znaménka nehraje, viz také poznámka dále).


Speciality

Lze použít přetypování, ale musíte tomu rozumět. Příklad tisku 64bit čísla, které je původně bez znaméka, jako číslo se znaménkem :

uint64_t hodnota64;

hodnota64 = 1234;

printf("hodnota je %lld \n", (int64_t) hodnota64); // vytiskne 1234


Ale:

uint64_t hodnota64;

hodnota64 = 0x8FFFFFFF;

printf("hodnota je %d \n", (int64_t) hodnota64); // vytiskne -1879048193 

Takže pozor, ať nejste zmateni.

V 64bit je např. -1 (signed) fyzicky (v paměti kde proměnná leží) reprezentována jako 0xFFFFFFFFFFFFFFFF (unsigned) atd. viz následující tabulka:

 skutečná binární hodnota         | 32-bit signed | 32-bit unsigned | skutečná binární hodnota                                         | 64-bit signed |    64-bit unsigned |
 (32-bit)                         | FC signed int |  FC unsiged int | (64-bit)                                                         |    FC int64_t |        FC uint64_t |
----------------------------------+---------------+-----------------+------------------------------------------------------------------+---------------+--------------------+
 00000000000000000000000000000000 |             0 |               0 | 0000000000000000000000000000000000000000000000000000000000000000 |             0 |                  0 |
 00000000000000000000000000000001 |             1 |               1 | 0000000000000000000000000000000000000000000000000000000000000001 |             1 |                  1 | 
 00000000000000001111111111111111 |         65535 |           65535 | 0000000000000000000000000000000000000000000000001111111111111111 |         65535 |              65535 |
 01111111111111111111111111111111 |    2147483647 |      2147483647 | 0000000000000000000000000000000001111111111111111111111111111111 |    2147483647 |         2147483647 |
 10000000000000000000000000000000 |   -2147483648 |      2147483648 | 1111111111111111111111111111111110000000000000000000000000000000 |   -2147483648 | 0xFFFFFFFF80000000 |
 10000000000000000000000000000001 |   -2147483647 |      2147483649 | 1111111111111111111111111111111110000000000000000000000000000001 |   -2147483647 | 0xFFFFFFFF80000001 |
 10000000000000001111111111111111 |   -2147418113 |      2147549183 | 1111111111111111111111111111111110000000000000001111111111111111 |   -2147418113 | 0xFFFFFFFF8000FFFF |
 11111111111111111111111111111111 |            -1 |      4294967295 | 1111111111111111111111111111111111111111111111111111111111111111 |            -1 | 0xFFFFFFFFFFFFFFFF |

Zkuste si to sami (např. v nějaké vhodné Kalkulačce) a uvidíte sami.

Pozor na nastavování z 32bit do 64bit

Pozor na to, jak jsou v jednotlivých typech (32bit oproti 64bit) reprezentovány záporná čísla.

Příklad:

unsigned int hodnota32;

hodnota32 = 0x8FFFFFFF // což také odpovídá tomuto: -1879048193 (signed)

int64_t h64s;

h64s = hodnota32; 

// a pozor - h64s je teď uloženo v paměti jako: ( 0xFFFFFFFF8FFFFFFF unsigned ) což odpovídá (-1879048193 signed).

Nenechte se zmást - je to správně. Nastudujte si to. Jde jen o to si uvědomit jak to vše funguje.

Proto kde můžete, používejte čistě a jen uint64_t a vyhnete se tomu (ale nebudete mít záporný rozsah, což často nevadí, a pak jste v klidu a nemusíte na toto myslet).

Samozřejmě pro if (pro podmínky) platí to samé co pro 32bit čísla - if porovnává dvě strany, např. if (a<b) { něco(); }; . Pokud se porovnávají dvě strany a obě jsou signed, výsledek a proces porovnání je také signed. Ale jakmile je jedno z nich (nebo obě strany) unsigned, pak se všechny strany nejprve převedou na unsigned, a pak se provede porovnání a výsledek je také unsigned. Toto je dle C standardu, a už se na tom spousta vývojářů spálilo, dejte si proto pozor.


Omezení při inicializaci 64bit čísla

V současné verzi FULL-C umí SDS jen 32bitové konstanty. To se v nové verzi upraví a bude umět i 64bit konstanty, ale teď je ještě neumí.

Řešení je snadné, použijte "výpočet" pro nastavení výchozí hodnoty (je-li třeba nějaká nenulová).

uint64_t x;

x = 1024; // toto je zápis 32bit konstanty do uint64_t

x *= 1000000000;

printf("hodnota = %llu \n", x); // vytiskne číslo 1024000000000 což je delší než 32bitů, takže to funguje 
(pro info: v hexa tvaru to je: 0xEE6B280000).

Jak snadné.