Obsah
1. Rezervovaná klíčová slova programovacího jazyka C3
2. Nejkratší možný program: definice prázdné funkce main
4. Klasický program typu „Hello, world!“
6. Volání nativní céčkovské funkce
8. Automatické konverze celočíselných hodnot do proměnných typu bool?bool
9. Explicitní konverze mezi celými čísly a typy bool
10. Zjištění velikosti obsazeného bloku paměti v čase překladu
12. Zápis konstant celočíselných datových typů
13. Zjištění velikosti obsazeného bloku paměti pro celočíselné datové typy
14. Automatické a explicitní konverze mezi celočíselnými datovými typy
15. Numerické hodnoty s plovoucí řádovou čárkou
16. Velmi užitečný datový typ – vektor
17. Operace prováděné s celými vektory
18. Zjištění velikosti bloku obsazeného vektorem v operační paměti
19. Repositář s demonstračními příklady
1. Rezervovaná klíčová slova programovacího jazyka C3
V programovacím jazyku C3 je definováno poměrně velké množství klíčových slov – možná až moc velký počet na céčkovský jazyk. Jedná se o následující slova, mezi nimiž mj. nalezneme i jména základních datových typů:
void bool char double float float16 int128 ichar int iptr isz long short uint128 uint ulong uptr ushort usz float128 any fault typeid assert asm bitstruct break case catch const continue alias default defer typedef do else enum extern false for foreach foreach_r fn tlocal if inline import macro module nextcase null return static struct switch true try union var while attrdef
Některá klíčová slova začínají znakem dolaru a většina z nich se používá v makrech, což je téma, kterému se budeme věnovat příště. Makra v C3 jsou zcela odlišná od maker známých z jazyka C:
$alignof $assert $case $default $defined $echo $embed $exec $else $endfor $endforeach $endif $endswitch $eval $evaltype $error $extnameof $for $foreach $if $include $nameof $offsetof $qnameof $sizeof $stringify $switch $typefrom $typeof $vacount $vatype $vaconst $vaarg $vaexpr $vasplat
break default func interface select case defer go map struct chan else goto package switch const fallthrough if range type continue for import return var
2. Nejkratší možný program: definice prázdné funkce main
Podívejme se nyní na to, jak vypadá nejkratší možný program zapsaný v jazyce C3. Není tu nutné explicitně zapisovat jméno modulu atd. atd. – pouze postačuje definice prázdné funkce nazvané main. Jak jsme si již řekli minule, začíná definice funkce klíčovým slovem fn, za kterým následuje jméno funkce, popř. její parametry v závorkách:
fn void main()
{
}
3. Definice jména modulu
Na prvním řádku ve zdrojovém kódu může být specifikováno jméno modulu, v jehož rámci budou definovány všechny další symboly (globální proměnné, funkce atd.). Před jménem modulu je uvedeno klíčové slovo module, takže celý zápis vypadá následovně:
module program_stub;
fn void main()
{
}
Jméno modulu má vliv i na jméno výsledného spustitelného souboru – to se již nebude odvozovat od jména souboru se zdrojovým kódem, ale právě od jména modulu.
4. Klasický program typu „Hello, world!“
Již téměř 47 let, konkrétně od vydání slavné knihy The C Programming Language, je dobrým zvykem ukazovat základní vlastnosti nějakého programovacího jazyka na programu typu „Hello, world!“. Můžeme postupovat stejně – v C3 tento program vypadá následovně:
module hello_world;
import std::io;
fn void main()
{
io::printn("Hello, world!");
}
Zde jsou skutečně ukázány některé zajímavé vlastnosti jazyka C3, konkrétně jeho práce s moduly (definice vlastního modulu a import jiného modulu), práce se jmennými prostory (tím se C3 do značné míry podobá již výše zmíněnému jazyku Go) i to, že prakticky veškeré definice začínají klíčovým slovem, zatímco v klasickém céčku začínají jménem typu (výjimkou je asi jen typedef).
5. Návratová hodnota procesu
V případě, že má proces vracet nějakou celočíselnou hodnotu (odlišnou od nuly) do volajícího procesu, typicky do shellu, postačuje tuto hodnotu vrátit z funkce main, a to naprosto stejným způsobem, jako je tomu v jazyku C. Nemusíme tedy používat obezličky typu os.Exit, sys.exit atd.:
module exit_value;
import std::io;
fn int main()
{
io::printn("Hello, world!");
return 42;
}
Ukázka použití:
$ c3c compile 04_exit_value.c3 Program linked to executable './exit_value'. $ ./exit_value Hello, world! $ echo $? 42
6. Volání nativní céčkovské funkce
Jednou z nejdůležitějších vlastností programovacího jazyka C3 je jeho schopnost bezproblémového volání céčkovských funkcí, například funkcí definovaných ve standardní céčkovské knihovně. Díky tomu je možné C3 relativně snadno nasadit v ekosystému postaveném okolo jazyka C, aniž by bylo nutné „znovuvynalézat“ FFI atd.
Vyzkoušejme si to na příkladu volání céčkovské funkce puts ze standardní knihovny. Tato funkce jako svůj parametr akceptuje řetězec; přičemž řetězce jsou v C3 prakticky stejné, jako řetězce v C (akorát je plně podporováno UTF-8). V příkladu importujeme céčkovskou knihovnu libc tak, jakoby se jednalo o běžný modul v C3, akorát bez jmenného prostoru. Díky tomu je možné volat funkci puts, která je v této knihovně definována:
module c_function_call;
import libc;
extern fn int puts(char*);
fn void main()
{
puts("Hello, world!");
}
7. Datový typ bool
Jazyk C3 se od klasického céčka v některých ohledech odlišuje. Týká se to mj. i typového systému, takže se nyní pokusíme na některé rozdíly upozornit. V jazyku C3 je možné, podobně jako v mnoha dalších programovacích jazycích, pracovat s hodnotami typu bool, tj. pravdivostními hodnotami true a false. Základní způsob práce s těmito hodnotami je dobře pochopitelný:
module bool_type;
import std::io;
fn void main()
{
bool x = true;
bool y = false;
io::printf("Bool value=%b\n", x);
io::printf("Bool value=%b\n", y);
}
Výsledky:
Bool value=1 Bool value=0
I když tento příklad vypsat numerické výsledky, není v C3 možné s hodnotami typu bool provádět například součty (což například v Pythonu je možné):
module bool_add;
import std::io;
fn void main()
{
bool x = true;
bool y = false;
io::printf("%d\n", x+y);
}
Tento příklad není přeložitelný, což je ostatně dobře:
5: {
6: bool x = true;
7: bool y = false;
8: io::printf("%d\n", x+y);
^^^
(/home/ptisnovs/src/c3-examples/c3-basics/1.c3:8:24) Error: Cannot do the addition 'bool' + 'bool'.
8. Automatické konverze celočíselných hodnot do proměnných typu bool?
V některých programovacích jazycích je typ bool chápán jako podmnožina celočíselných datových typů, což například umožňuje do proměnné typu bool přiřadit celočíselnou hodnotu. V jazyku C3 tomu tak ovšem není a pokud se o podobné přiřazení pokusíme, dojde k chybě při překladu, což si můžeme velmi snadno ověřit na dalším demonstračním příkladu:
module int_to_bool_1;
import std::io;
fn void main()
{
bool x = 1;
bool y = 0;
bool z = 42;
io::printf("Bool value=%b\n", x);
io::printf("Bool value=%b\n", y);
io::printf("Bool value=%b\n", z);
}
Překladač jazyka C3 v tomto případě vypíše chybu u všech tří přiřazení, nikoli pouze u přiřazení posledního:
3:
4: fn void main()
5: {
6: bool x = 1;
^
(/home/ptisnovs/src/c3-examples/c3-basics/07_int_to_bool.c3:6:14) Error: 'int' cannot implicitly be converted to 'bool', but you may use a cast.
4: fn void main()
5: {
6: bool x = 1;
7: bool y = 0;
^
(/home/ptisnovs/src/c3-examples/c3-basics/07_int_to_bool.c3:7:14) Error: 'int' cannot implicitly be converted to 'bool', but you may use a cast.
5: {
6: bool x = 1;
7: bool y = 0;
8: bool z = 42;
^^
(/home/ptisnovs/src/c3-examples/c3-basics/07_int_to_bool.c3:8:14) Error: 'int' cannot implicitly be converted to 'bool', but you may use a cast.
9. Explicitní konverze mezi celými čísly a typy bool
V případě, že je vyžadováno provést konverzi celého čísla na typ bool, je nutné konverzi zapsat explicitně. Nulové hodnoty budou převedeny na false, ostatní hodnoty (včetně hodnot záporných) na true. Operace konverze se zapisuje naprosto stejným způsobem, jako v klasickém céčku, tedy následovně:
module int_to_bool_2;
import std::io;
fn void main()
{
bool x = (bool)1;
bool y = (bool)0;
bool z = (bool)42;
io::printf("Bool value=%b\n", x);
io::printf("Bool value=%b\n", y);
io::printf("Bool value=%b\n", z);
}
Výsledky:
Bool value=1 Bool value=0 Bool value=1
module int_to_bool_3;
import std::io;
fn void main()
{
bool x = bool(1);
bool y = bool(0);
bool z = bool(42);
io::printf("Bool value=%b\n", x);
io::printf("Bool value=%b\n", y);
io::printf("Bool value=%b\n", z);
}
Popis chyby je v tomto případě velmi dobře čitelný:
3:
4: fn void main()
5: {
6: bool x = bool(1);
^^^^^^^
(/home/ptisnovs/src/c3-examples/c3-basics/09_int_to_bool.c3:6:14) Error: A type cannot be followed by (), if you intended a cast, use '(type) expression'.
4: fn void main()
5: {
6: bool x = bool(1);
7: bool y = bool(0);
^^^^^^^
(/home/ptisnovs/src/c3-examples/c3-basics/09_int_to_bool.c3:7:14) Error: A type cannot be followed by (), if you intended a cast, use '(type) expression'.
5: {
6: bool x = bool(1);
7: bool y = bool(0);
8: bool z = bool(42);
^^^^^^^^
(/home/ptisnovs/src/c3-examples/c3-basics/09_int_to_bool.c3:8:14) Error: A type cannot be followed by (), if you intended a cast, use '(type) expression'.
10. Zjištění velikosti obsazeného bloku paměti v čase překladu
Mezi další užitečnou vlastnost programovacího jazyka C3 patří schopnost zjištění velikosti bloku, který se v operační paměti musí alokovat pro zadaný datový typ. Zatímco v céčku se pro tyto účely používá operátor sizeof, v jazyku C3 má každý datový typ definován pseudoatribut nazvaný sizeof. Přečtení velikosti paměťového bloku pro typ bool je tedy snadné:
module bool_sizeof;
import std::io;
fn void main()
{
io::printf("Bool size=%d\n", bool.sizeof);
}
Tento program by měl po svém překladu a spuštění vypsat velikost bloku reprezentovanou v bajtech:
Bool size=1
11. Celočíselné datové typy
Jazyk C3 programátorům nabízí běžnou „sadu“ celočíselných datových typů, a to jak typů se znaménkem, tak i bez znaménka. U všech těchto typů je definitoricky určena jejich velikost v bajtech i rozsah hodnot (minimální a maximální hodnota) – a to na všech platformách. Celočíselné typy se znaménkem používají dvojkový doplněk a pojmenovány jsou ichar, short, int, long a int128. Nejedná se o modifikátory velikosti, ale přímo o jména datových typů:
module int_types;
import std::io;
fn void main()
{
ichar a = '*';
short b = -42;
int c = -42;
long d = -42;
int128 e = -42;
io::printf("ichar value=%c\n", a);
io::printf("short value=%d\n", b);
io::printf("int value=%d\n", c);
io::printf("long value=%d\n", d);
io::printf("int128 value=%d\n", e);
}
Výsledky vypsané tímto demonstračním příkladem by měly vypadat následovně:
ichar value=* short value=-42 int value=-42 long value=-42 int128 value=-42
Celočíselné typy bez znaménka se jmenují char, ushort, uint, ulong a uint128:
module uint_types;
import std::io;
fn void main()
{
char a = '*';
ushort b = 42;
uint c = 42;
ulong d = 42;
uint128 e = 42;
io::printf("char value=%c\n", a);
io::printf("ushort value=%d\n", b);
io::printf("uint value=%d\n", c);
io::printf("ulong value=%d\n", d);
io::printf("uint128 value=%d\n", e);
}
Opět se podívejme na výsledky:
char value=* ushort value=42 uint value=42 ulong value=42 uint128 value=42
12. Zápis konstant celočíselných datových typů
Pokusme se nyní přeložit následující program, ve kterém do celočíselných proměnných přiřazujeme celočíselné hodnoty vypočtené v čase překladu (výrazy jsou konstantní):
module no_suffixes;
import std::io;
fn void main()
{
uint128 a = 100;
uint128 b = 100*100;
uint128 c = 100*100*100;
uint128 d = 100*100*100*100;
uint128 e = 100*100*100*100*100;
uint128 f = 100*100*100*100*100*100;
io::printf("a=%d\n", a);
io::printf("b=%d\n", b);
io::printf("c=%d\n", c);
io::printf("d=%d\n", d);
io::printf("e=%d\n", e);
io::printf("f=%d\n", f);
}
Tento zdrojový kód se sice přeloží, ale výsledky budou pro poslední dvě hodnoty špatné, protože interně došlo k přetečení (resp. zde k přenosu) při výpočtu konstant ukládaných do proměnných:
a=100 b=10000 c=1000000 d=100000000 e=1410065408 f=340282366920938463463374607431040831488
Pro korektní výpočty je nutné alespoň u jednoho čísla použít suffix, který určí typ této konstanty. Konkrétně pro hodnoty typu uint128 je tímto suffixem sekvence znaků u128:
module no_suffixes;
import std::io;
fn void main()
{
uint128 a = 100u128;
uint128 b = 100u128*100;
uint128 c = 100u128*100*100;
uint128 d = 100u128*100*100*100;
uint128 e = 100u128*100*100*100*100;
uint128 f = 100u128*100*100*100*100*100;
io::printf("a=%d\n", a);
io::printf("b=%d\n", b);
io::printf("c=%d\n", c);
io::printf("d=%d\n", d);
io::printf("e=%d\n", e);
io::printf("f=%d\n", f);
}
Výsledky jsou nyní korektní:
a=100 b=10000 c=1000000 d=100000000 e=10000000000 f=1000000000000
Pro úplnost si vypišme všechny podporované suffixy pro celočíselné hodnoty:
| suffix | typ |
|---|---|
| i8 | ichar |
| i16 | short |
| i32 | int |
| i64 | long |
| i128 | int128 |
| u8 | char |
| u16 | ushort |
| u32 | uint |
| u | uint |
| u64 | ulong |
| u128 | uint128 |
13. Zjištění velikosti obsazeného bloku paměti pro celočíselné datové typy
I u celočíselných datových typů můžeme zjistit jejich velikost v paměti s využitím pseudoatributu sizeof. Nejdříve si tento postup vyzkoušíme u typů se znaménkem:
module uint_types;
import std::io;
fn void main()
{
io::printf("sizeof ichar = %d\n", ichar.sizeof);
io::printf("sizeof short = %d\n", short.sizeof);
io::printf("sizeof int = %d\n", int.sizeof);
io::printf("sizeof long = %d\n", long.sizeof);
io::printf("sizeof int128 = %d\n", int128.sizeof);
}
Výsledky by neměly být překvapivé:
sizeof ichar = 1 sizeof short = 2 sizeof int = 4 sizeof long = 8 sizeof int128 = 16
Stejný postup použijeme pro zjištění velikosti celočíselných datových typů bez znaménka:
module uint_types;
import std::io;
fn void main()
{
io::printf("sizeof char = %d\n", char.sizeof);
io::printf("sizeof ushort = %d\n", ushort.sizeof);
io::printf("sizeof uint = %d\n", uint.sizeof);
io::printf("sizeof ulong = %d\n", ulong.sizeof);
io::printf("sizeof uint128 = %d\n", uint128.sizeof);
}
Výsledky:
sizeof char = 1 sizeof ushort = 2 sizeof uint = 4 sizeof ulong = 8 sizeof uint128 = 16
14. Automatické a explicitní konverze mezi celočíselnými datovými typy
Další odlišnost programovacího jazyka C3 od klasického céčka zjistíme při pokusu o konverzi mezi celočíselnými datovými typy. Pokud je konverze prováděna z typů s menším rozsahem hodnot na typy s větším rozsahem, bude vše v pořádku (podle očekávání):
module int_conversions;
import std::io;
fn void main()
{
ichar a = 100;
short b = 100*100;
int c = 100*100*100;
io::printf("a=%d\n", a);
io::printf("b=%d\n", b);
io::printf("c=%d\n", c);
int x = a;
int y = b;
int z = c;
io::printf("x=%d\n", x);
io::printf("y=%d\n", y);
io::printf("z=%d\n", z);
}
Výsledky jsou zcela korektní:
a=100 b=10000 c=1000000 x=100 y=10000 z=1000000
Vyzkoušejme si nyní přeložit program pro konverzi z typů s větší bitovou šířkou na typy s šířkou menší (převod int na short):
module int_conversions;
import std::io;
fn void main()
{
ichar a = 100;
short b = 100*100;
int c = 100*100*100;
io::printf("a=%d\n", a);
io::printf("b=%d\n", b);
io::printf("c=%d\n", c);
short x = a;
short y = b;
short z = c;
io::printf("x=%d\n", x);
io::printf("y=%d\n", y);
io::printf("z=%d\n", z);
}
Tyto konverze (pokud by měly být provedeny implicitně) nejsou povoleny a překladač jazyka C3 programátora o nepovolené operaci informuje:
14: short x = a;
15: short y = b;
16: short z = c;
^
(/home/ptisnovs/src/c3-examples/c3-basics/18_int_conversions.c3:16:15) Error: 'int' cannot implicitly be converted to 'short', but you may use a cast.
Konverzi si ovšem můžeme vynutit explicitním zápisem přetypování – viz zvýrazněnou část zdrojového kódu:
module int_conversions;
import std::io;
fn void main()
{
ichar a = 100;
short b = 100*100;
int c = 100*100*100;
io::printf("a=%d\n", a);
io::printf("b=%d\n", b);
io::printf("c=%d\n", c);
short x = (short)a;
short y = (short)b;
short z = (short)c;
io::printf("x=%d\n", x);
io::printf("y=%d\n", y);
io::printf("z=%d\n", z);
}
Nyní ke konverzím dojde, ale (podle očekávání) dojde k přetečení hodnoty:
a=100 b=10000 c=1000000 x=100 y=10000 z=16960
15. Numerické hodnoty s plovoucí řádovou čárkou
Programovací jazyk C3 pochopitelně podporuje i datové typy reprezentující numerické hodnoty s plovoucí řádovou čárkou. Kromě standardních typů float a double (dle IEEE 754) mohou být podporovány i typy float16 (half float), bfloat16 (brain floating point) a na druhé straně spektra pak float128. Ovšem podpora těchto typů se může lišit v závislosti na použité architektuře. Na x86–64 lze využívat float16 i float128, ale nikoli bfloat16:
module float_types;
import std::io;
fn void main()
{
float16 x = 1e1;
float y = 1e10;
double z = 1e100;
float128 w = 1e100;
io::printf("x=%s\n", x);
io::printf("y=%s\n", y);
io::printf("z=%s\n", z);
io::printf("w=%s\n", w);
}
16. Velmi užitečný datový typ – vektor
V programovacím jazyce C3 nalezneme jeden důležitý datový typ, který má sice (z mnoha dobrých důvodů) různá omezení, ovšem v praxi je velmi užitečný. Jedná se o vektory. Tento datový typ je generický, protože je možné (resp. přesněji řečeno nutné) explicitně určit typ prvků vektoru. Počet prvků musí být znám již v době překladu, což je největší rozdíl oproti klasickým polím. Ovšem díky tomu, že překladač zná délku vektoru, může s nimi provádět optimalizované operace, typicky s využitím vektorových instrukcí (SIMD) nabízených moderními mikroprocesory. I z tohoto důvodu platí ještě jedno omezení: typy prvků vektorů jsou omezeny na numerické hodnoty, pravdivostní hodnoty popř. na ukazatele.
V dalším demonstračním příkladu je ukázáno, jakým způsobem se deklaruje proměnná typu vektor. Povšimněte si, že počet prvků vektoru je konstantní a musí být umístěn mezi úhlové závorky (podtržená část kódu):
module float_types;
import std::io;
fn void main()
{
int[<10>] a = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
io::printf("a=%s\n", a);
}
Po překladu a spuštění tohoto příkladu se celý vektor vypíše na standardní výstup (povšimněte si způsobu výpisu):
a=[<1, 2, 3, 4, 5, 6, 7, 8, 9, 10>]
17. Operace prováděné s celými vektory
V čem ovšem spočívá užitečnost vektorů v porovnání s běžnými (popř. s dynamicky alokovanými) poli? Nad prvky vektorů jsou definovány například běžné aritmetické operace. Ty se provádí s odpovídajícími si prvky vektorů, takže vektory lze sečíst, odečíst atd. Navíc je možné dva vektory porovnat na rovnost nebo nerovnost, přičemž výsledkem bude jediná pravdivostní hodnota true či false, která nezávisí na tom, zda se jedná o odlišné instance či o jediný objekt v paměti.
V dalším demonstračním příkladu jsou ukázány základní aritmetické operace nad odpovídajícími si prvky vektorů. Za těmito operacemi jsou provedeny aritmetické operace mezi vektorem a skalární hodnotou (skalární hodnota je „roztažena“ do formy vektoru a teprve poté se operace provede). A nakonec si otestujeme porovnání různých vektorů na rovnost a nerovnost:
module float_types;
import std::io;
fn void main()
{
int[<10>] a = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
int[<10>] b = {2, 2, 2, 2, 2, 2, 2, 2, 2, 2};
io::printf("a=%s\n", a);
io::printf("b=%s\n", b);
io::printn();
io::printf("a+b=%s\n", a+b);
io::printf("a-b=%s\n", a-b);
io::printf("a*b=%s\n", a*b);
io::printf("a/b=%s\n", a/b);
io::printn();
io::printf("a+2=%s\n", a+2);
io::printf("a-2=%s\n", a-2);
io::printf("a*2=%s\n", a*2);
io::printf("a/2=%s\n", a/2);
io::printn();
io::printf("a==b=%s\n", a==b);
io::printf("a!=b=%s\n", a!=b);
io::printf("a==a=%s\n", a==a);
io::printf("a!=a=%s\n", a!=a);
io::printn();
io::printf("%s\n", a-a==b-b);
io::printf("%s\n", a+b==b+a);
}
Po překladu a spuštění tohoto příkladu se nejdříve vypíšou oba vektory:
a=[<1, 2, 3, 4, 5, 6, 7, 8, 9, 10>] b=[<2, 2, 2, 2, 2, 2, 2, 2, 2, 2>]
V dalším kroku se zobrazí výsledek provedení aritmetických operací mezi prvky vektorů:
a+b=[<3, 4, 5, 6, 7, 8, 9, 10, 11, 12>] a-b=[<-1, 0, 1, 2, 3, 4, 5, 6, 7, 8>] a*b=[<2, 4, 6, 8, 10, 12, 14, 16, 18, 20>] a/b=[<0, 1, 1, 2, 2, 3, 3, 4, 4, 5>]
Následuje blok s výsledky provedení aritmetických operací mezi vektorem a skalární hodnotou:
a+2=[<3, 4, 5, 6, 7, 8, 9, 10, 11, 12>] a-2=[<-1, 0, 1, 2, 3, 4, 5, 6, 7, 8>] a*2=[<2, 4, 6, 8, 10, 12, 14, 16, 18, 20>] a/2=[<0, 1, 1, 2, 2, 3, 3, 4, 4, 5>]
Nakonec jsou vypsány výsledky porovnání vektorů:
a==b=false a!=b=true a==a=true a!=a=false true true
18. Zjištění velikosti bloku obsazeného vektorem v operační paměti
I pro vektory je definována vlastnost sizeof, která nám umožňuje zjistit (pochopitelně již v čase překladu), jakou velikost bude mít vektor po své alokaci v operační paměti. V dnešním předposledním demonstračním příkladu zjistíme velikosti bloků pro desetiprvkové vektory, přičemž se budou lišit typy prvků:
module float_types;
import std::io;
fn void main()
{
io::printf("10 items of bool: %d\n", bool[<10>].sizeof);
io::printf("10 items of ichar: %d\n", ichar[<10>].sizeof);
io::printf("10 items of short: %d\n", short[<10>].sizeof);
io::printf("10 items of int: %d\n", int[<10>].sizeof);
io::printf("10 items of long: %d\n", long[<10>].sizeof);
io::printf("10 items of int128: %d\n", int128[<10>].sizeof);
io::printf("10 items of float16: %d\n", float16[<10>].sizeof);
io::printf("10 items of float: %d\n", float[<10>].sizeof);
io::printf("10 items of double: %d\n", double[<10>].sizeof);
io::printf("10 items of float128: %d\n", float128[<10>].sizeof);
}
Z vypsaných hodnot je patrné, že se obecně obsadí větší paměťový prostor, než který odpovídá výsledku počet_prvků * sizeof prvek:
10 items of bool: 16 10 items of ichar: 16 10 items of short: 32 10 items of int: 64 10 items of long: 128 10 items of int128: 256 10 items of float16: 32 10 items of float: 64 10 items of double: 128 10 items of float128: 256
Jak přesně je délka alokovaného bloku odvozena od počtu prvků vektoru zjistíme v dnešním posledním demonstračním příkladu. V něm si necháme vypočítat velikost alokovaného bloku pro vektory se shodnými typy prvků, ale s odlišnou délkou:
module float_types;
import std::io;
fn void main()
{
io::printf("1 items of int: %d\n", int[<1>].sizeof);
io::printf("2 items of int: %d\n", int[<2>].sizeof);
io::printf("3 items of int: %d\n", int[<3>].sizeof);
io::printf("4 items of int: %d\n", int[<4>].sizeof);
io::printf("5 items of int: %d\n", int[<5>].sizeof);
io::printf("6 items of int: %d\n", int[<6>].sizeof);
io::printf("7 items of int: %d\n", int[<7>].sizeof);
io::printf("8 items of int: %d\n", int[<8>].sizeof);
io::printf("9 items of int: %d\n", int[<9>].sizeof);
io::printf("10 items of int: %d\n", int[<10>].sizeof);
io::printf("11 items of int: %d\n", int[<11>].sizeof);
io::printf("12 items of int: %d\n", int[<12>].sizeof);
io::printf("13 items of int: %d\n", int[<13>].sizeof);
io::printf("14 items of int: %d\n", int[<14>].sizeof);
io::printf("15 items of int: %d\n", int[<15>].sizeof);
}
Výsledky pro situaci, kdy sizeof int==4:
1 items of int: 4 2 items of int: 8 3 items of int: 16 4 items of int: 16 5 items of int: 32 6 items of int: 32 7 items of int: 32 8 items of int: 32 9 items of int: 64 10 items of int: 64 11 items of int: 64 12 items of int: 64 13 items of int: 64 14 items of int: 64 15 items of int: 64
19. Repositář s demonstračními příklady
Dnes i minule ukázané demonstrační příklady byly uloženy do repositáře dostupného na adrese https://github.com/tisnik/c3-examples. Následují odkazy na jednotlivé příklady (či jejich nedokončené části):
| # | Příklad | Stručný popis | Adresa |
|---|---|---|---|
| 1 | factorial.c3 | realizace výpočtu faktoriálu | https://github.com/tisnik/c3-examples/blob/master/introduction/factorial.c3 |
| 2 | factorial_macro.c3 | výpočet faktoriálu konkrétní hodnoty implementovaný formou makra | https://github.com/tisnik/c3-examples/blob/master/introduction/factorial_macro.c3 |
| 3 | swap_macro.c3 | makro realizující prohození dvou hodnot | https://github.com/tisnik/c3-examples/blob/master/introduction/swap_macro.c3 |
| 4 | renderer.c | výpočet a vykreslení Juliovy množiny implementovaný v jazyku C | https://github.com/tisnik/c3-examples/blob/master/introduction/renderer.c |
| 5 | renderer_v1.c3 | definice datové struktury s rozměry rastrového obrázku a skeleton všech funkcí | https://github.com/tisnik/c3-examples/blob/master/introduction/renderer_v1.c3 |
| 6 | renderer_v2.c3 | anotace parametrů funkcí typu ukazatel (pointer) | https://github.com/tisnik/c3-examples/blob/master/introduction/renderer_v2.c3 |
| 7 | renderer_v3.c3 | statická kontrola, zda se nepředávají neinicializované ukazatele | https://github.com/tisnik/c3-examples/blob/master/introduction/renderer_v3.c3 |
| 8 | renderer_v4.c3 | runtime kontrola, zda se nepředávají neinicializované ukazatele | https://github.com/tisnik/c3-examples/blob/master/introduction/renderer_v4.c3 |
| 9 | renderer_v5.c3 | první (nekorektní) varianta funkce pro inicializaci barvové palety | https://github.com/tisnik/c3-examples/blob/master/introduction/renderer_v5.c3 |
| 10 | renderer_v6.c3 | druhá (korektní) varianta funkce pro inicializaci barvové palety | https://github.com/tisnik/c3-examples/blob/master/introduction/renderer_v6.c3 |
| 11 | renderer_v7.c3 | volání knihovní I/O funkce a volání nativní céčkovské funkce | https://github.com/tisnik/c3-examples/blob/master/introduction/renderer_v7.c3 |
| 12 | renderer_v8.c3 | plně funkční program pro výpočet a vykreslení Juliovy množiny | https://github.com/tisnik/c3-examples/blob/master/introduction/renderer_v8.c3 |
| 13 | 01_just_main.c3 | struktura nejjednoduššího programu obsahujícího pouze prázdnou funkci main | https://github.com/tisnik/c3-examples/blob/master/c3-basics/01_just_main.c3 |
| 14 | 02_module_name.c3 | struktura programu s uvedeným plným jménem modulu | https://github.com/tisnik/c3-examples/blob/master/c3-basics/02_module_name.c3 |
| 15 | 03_hello_world.c3 | klasický program typu „Hello, world!“ napsaný v jazyku C3 | https://github.com/tisnik/c3-examples/blob/master/c3-basics/03_hello_world.c3 |
| 16 | 04_exit_value.c3 | ukončení procesu s předáním návratového kódu zpět volajícímu programu | https://github.com/tisnik/c3-examples/blob/master/c3-basics/04_exit_value.c3 |
| 17 | 05_c_function.c3 | zavolání funkce definované v knihovně programovacího jazyka C | https://github.com/tisnik/c3-examples/blob/master/c3-basics/05_c_function.c3 |
| 18 | 06_bool_type.c3 | definice proměnných typu pravdivostní hodnota (bool) | https://github.com/tisnik/c3-examples/blob/master/c3-basics/06_bool_type.c3 |
| 19 | 07_int_to_bool.c3 | implicitní převod hodnoty typu int na pravdivostní hodnotu (nekorektní řešení) | https://github.com/tisnik/c3-examples/blob/master/c3-basics/07_int_to_bool.c3 |
| 20 | 08_int_to_bool.c3 | explicitní převod hodnoty typu int na pravdivostní hodnotu (korektní řešení) | https://github.com/tisnik/c3-examples/blob/master/c3-basics/08_int_to_bool.c3 |
| 21 | 09_int_to_bool.c3 | explicitní převod hodnoty typu int na pravdivostní hodnotu (nekorektní řešení) | https://github.com/tisnik/c3-examples/blob/master/c3-basics/09_int_to_bool.c3 |
| 22 | 10_bool_sizeof.c3 | zjištění velikosti paměti obsazené hodnotou typu bool | https://github.com/tisnik/c3-examples/blob/master/c3-basics/10_bool_sizeof.c3 |
| 23 | 11_int_types.c3 | definice proměnných typu celé číslo se znaménkem s různou bitovou šířkou | https://github.com/tisnik/c3-examples/blob/master/c3-basics/11_int_types.c3 |
| 24 | 12_uint_types.c3 | definice proměnných typu celé číslo bez znaménka s různou bitovou šířkou | https://github.com/tisnik/c3-examples/blob/master/c3-basics/12_uint_types.c3 |
| 25 | 13_no_suffixes.c3 | celočíselné konstanty bez uvedení suffixu (bitové šířky) | https://github.com/tisnik/c3-examples/blob/master/c3-basics/13_no_suffixes.c3 |
| 26 | 14_suffixes.c3 | celočíselné konstanty s uvedením sufficu (bitové šířky) | https://github.com/tisnik/c3-examples/blob/master/c3-basics/14_suffixes.c3 |
| 27 | 15_int_sizeof.c3 | zjištění velikosti paměti obsazené celočíselnými hodnotami se znaménkem | https://github.com/tisnik/c3-examples/blob/master/c3-basics/15_int_sizeof.c3 |
| 28 | 16_uint_sizeof.c3 | zjištění velikosti paměti obsazené celočíselnými hodnotami bez znaménka | https://github.com/tisnik/c3-examples/blob/master/c3-basics/16_uint_sizeof.c3 |
| 29 | 17_int_conversions.c3 | korektní převody mezi celočíselnými hodnotami s různou bitovou šířkou | https://github.com/tisnik/c3-examples/blob/master/c3-basics/17_int_conversions.c3 |
| 30 | 18_int_conversions.c3 | nekorektní převody mezi celočíselnými hodnotami s různou bitovou šířkou | https://github.com/tisnik/c3-examples/blob/master/c3-basics/18_int_conversions.c3 |
| 31 | 19_int_conversions.c3 | explicitní převody a přetečení hodnot | https://github.com/tisnik/c3-examples/blob/master/c3-basics/19_int_conversions.c3 |
| 32 | 20_float_types.c3 | definice proměnných typu numerická hodnota s plovoucí řádovou čárkou (tečkou) | https://github.com/tisnik/c3-examples/blob/master/c3-basics/20_float_types.c3 |
| 33 | 21_vector_type.c3 | definice vektoru obsahujícího celočíselné hodnoty | https://github.com/tisnik/c3-examples/blob/master/c3-basics/21_vector_type.c3 |
| 34 | 22_vector_operations.c3 | základní operace s celými vektory | https://github.com/tisnik/c3-examples/blob/master/c3-basics/22_vector_operations.c3 |
| 35 | 23_vector_sizes.c3 | zjištění a tisk velikosti vektorů (různé datové typy prvků vektorů, shodná délka) | https://github.com/tisnik/c3-examples/blob/master/c3-basics/23_vector_sizes.c3 |
| 36 | 24_vector_sizes.c3 | zjištění a tisk velikosti vektorů (stejné datové typy prvků vektorů, odlišná délka) | https://github.com/tisnik/c3-examples/blob/master/c3-basics/24_vector_sizes.c3 |
20. Odkazy na Internetu
- The C3 Programming Language
https://c3-lang.org/ - C3 For C Programmers
https://c3-lang.org/language-overview/primer/ - C3 is a C-like language trying to be an incremental improvement over C rather than a whole new language
https://www.reddit.com/r/ProgrammingLanguages/comments/oohij6/c3_is_a_clike_language_trying_to_be_an/ - Tiobe index
https://www.tiobe.com/tiobe-index/ - PYPL PopularitY of Programming Language
https://pypl.github.io/PYPL.html - C3 Tutorial
https://learn-c3.org/ - History of programming languages
https://devskiller.com/history-of-programming-languages/ - History of programming languages (Wikipedia)
https://en.wikipedia.org/wiki/History_of_programming_languages - D language
https://dlang.org/ - Zig programming language
https://ziglang.org/ - V language
https://vlang.io/ - D programming language
https://en.wikipedia.org/wiki/D_(programming_language) - Zig programming language (Wikipedia)
https://en.wikipedia.org/wiki/Zig_(programming_language) - V programming language (Wikipedia)
https://en.wikipedia.org/wiki/V_(programming_language) - Syntax highlighting for C3's programming language
https://github.com/Airbus5717/c3.vim - Go factorial
https://gist.github.com/esimov/9622710 - Generational list of programming languages
https://en.wikipedia.org/wiki/Generational_list_of_programming_languages - The Language Tree: Almost Every Programming Language Ever Made
https://github.com/Phileosopher/langmap - List of C-family programming languages
https://en.wikipedia.org/wiki/List_of_C-family_programming_languages - Compatibility of C and C++
https://en.wikipedia.org/wiki/Compatibility_of_C_and_C%2B%2B - C++23: compatibility with C
https://www.sandordargo.com/blog/2023/08/23/cpp23-c-compatibility - Can C++ Run C Code? Understanding Language Compatibility
https://www.codewithc.com/can-c-run-c-code-understanding-language-compatibility/ - C3: Comparisons With Other Languages
https://c3-lang.org/faq/compare-languages/ - C3 Programming Language Gains Traction as Modern C Alternative
https://biggo.com/news/202504040125_C3_Programming_Language_Alternative_to_C - The case against a C alternative
https://c3.handmade.network/blog/p/8486-the_case_against_a_c_alternative - C (programming language) Alternatives
https://alternativeto.net/software/c-programming-language-/ - Seriál Programovací jazyk Go
https://www.root.cz/serialy/programovaci-jazyk-go/ - Is C3 the Underdog That Will Overtake Zig and Odin?
https://bitshifters.cc/2025/05/22/c3-c-tradition.html - „Hello, World!“ program
https://en.wikipedia.org/wiki/%22Hello%2C_World!%22_program - The C Programming Language
https://en.wikipedia.org/wiki/The_C_Programming_Language