Programovací jazyk C3: datové typy pro moderní architektury

18. 9. 2025
Doba čtení: 26 minut

Sdílet

Programovací jazyk C3
Autor: Root.cz s využitím Zoner AI
Budeme se zabývat základy tohoto jazyka, jeho odlišnostmi od C a naopak novými vlastnostmi. Ty se týkají i tak základního konceptu, jakým jsou datové typy. Ty jsou v C3 definovány tak, aby odpovídaly moderním architekturám.

Obsah

1. Rezervovaná klíčová slova programovacího jazyka C3

2. Nejkratší možný program: definice prázdné funkce main

3. Definice jména modulu

4. Klasický program typu „Hello, world!“

5. Návratová hodnota procesu

6. Volání nativní céčkovské funkce

7. Datový typ bool

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

11. Celočíselné datové typy

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

20. Odkazy na Internetu

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
Poznámka: zajímavé je, že v částečně podobném jazyce Go je rezervovaných klíčových slov mnohem méně – konkrétně jen 25. Je tomu tak mj. i z toho důvodu, že sem nespadají jména základních datových typů:
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()
{
}
Poznámka: v tomto případě bude jméno spustitelného souboru získaného překladem (c3c compile) odvozeno od jména souboru se zdrojovým kódem.

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.

Poznámka: do jisté míry se module podobá klíčovému slovu package z jazyka Go, ovšem v C3 není jméno modulu povinné a liší se i další detaily, ke kterým se ještě vrátíme.

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
Poznámka: povšimněte si, kolik rezervovaných klíčových slov jsme již použili, a to většinou bez nutnosti jejich podrobného popisu – jazyk C3 se podobá C do takové míry, že detailnější popis většinou není nutný.

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
Poznámka: skutečně musíme konverzi zapsat „céčkovským“ způsobem. Pokud se pokusíte o zápis známý z jazyka Go, bude při překladu nahlášena chyba:
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
Poznámka: pozor je nutné dávat především na typ char, který má v jiných jazycích odlišný význam (a může se jednat o typ se znaménkem či dokonce o hodnotu uloženou ve více bajtech).

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 float16float128, 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);
}
Poznámka: pochopitelně i pro tyto typy lze zjistit počty bajtů nutných pro jejich uložení v operační paměti. Opět se použije zápis jméno_typu.sizeof.

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
Poznámka: existují i metody pro práci s vektory. O těchto metodách se zmíníme v navazujícím textu.

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
Poznámka: v tomto příkladu není možné použít klasickou počítanou smyčku, protože délka vektoru musí být známa v čase překladu. Pomoci nám může makro, což je však téma na samostatný článek.

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/intro­duction/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/intro­duction/factorial_macro.c3
       
3 swap_macro.c3 makro realizující prohození dvou hodnot https://github.com/tisnik/c3-examples/blob/master/intro­duction/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/intro­duction/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/intro­duction/renderer_v1.c3
6 renderer_v2.c3 anotace parametrů funkcí typu ukazatel (pointer) https://github.com/tisnik/c3-examples/blob/master/intro­duction/renderer_v2.c3
7 renderer_v3.c3 statická kontrola, zda se nepředávají neinicializované ukazatele https://github.com/tisnik/c3-examples/blob/master/intro­duction/renderer_v3.c3
8 renderer_v4.c3 runtime kontrola, zda se nepředávají neinicializované ukazatele https://github.com/tisnik/c3-examples/blob/master/intro­duction/renderer_v4.c3
9 renderer_v5.c3 první (nekorektní) varianta funkce pro inicializaci barvové palety https://github.com/tisnik/c3-examples/blob/master/intro­duction/renderer_v5.c3
10 renderer_v6.c3 druhá (korektní) varianta funkce pro inicializaci barvové palety https://github.com/tisnik/c3-examples/blob/master/intro­duction/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/intro­duction/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/intro­duction/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

  1. The C3 Programming Language
    https://c3-lang.org/
  2. C3 For C Programmers
    https://c3-lang.org/language-overview/primer/
  3. 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/Pro­grammingLanguages/comments/o­ohij6/c3_is_a_clike_langu­age_trying_to_be_an/
  4. Tiobe index
    https://www.tiobe.com/tiobe-index/
  5. PYPL PopularitY of Programming Language
    https://pypl.github.io/PYPL.html
  6. C3 Tutorial
    https://learn-c3.org/
  7. History of programming languages
    https://devskiller.com/history-of-programming-languages/
  8. History of programming languages (Wikipedia)
    https://en.wikipedia.org/wi­ki/History_of_programming_lan­guages
  9. D language
    https://dlang.org/
  10. Zig programming language
    https://ziglang.org/
  11. V language
    https://vlang.io/
  12. D programming language
    https://en.wikipedia.org/wi­ki/D_(programming_language)
  13. Zig programming language (Wikipedia)
    https://en.wikipedia.org/wi­ki/Zig_(programming_langu­age)
  14. V programming language (Wikipedia)
    https://en.wikipedia.org/wi­ki/V_(programming_language)
  15. Syntax highlighting for C3's programming language
    https://github.com/Airbus5717/c3.vim
  16. Go factorial
    https://gist.github.com/e­simov/9622710
  17. Generational list of programming languages
    https://en.wikipedia.org/wi­ki/Generational_list_of_pro­gramming_languages
  18. The Language Tree: Almost Every Programming Language Ever Made
    https://github.com/Phileo­sopher/langmap
  19. List of C-family programming languages
    https://en.wikipedia.org/wi­ki/List_of_C-family_programming_languages
  20. Compatibility of C and C++
    https://en.wikipedia.org/wi­ki/Compatibility_of_C_and_C%2B%2B
  21. C++23: compatibility with C
    https://www.sandordargo.com/blog/2023/08/23/cpp­23-c-compatibility
  22. Can C++ Run C Code? Understanding Language Compatibility
    https://www.codewithc.com/can-c-run-c-code-understanding-language-compatibility/
  23. C3: Comparisons With Other Languages
    https://c3-lang.org/faq/compare-languages/
  24. C3 Programming Language Gains Traction as Modern C Alternative
    https://biggo.com/news/202504040125_C3_Pro­gramming_Language_Alterna­tive_to_C
  25. The case against a C alternative
    https://c3.handmade.networ­k/blog/p/8486-the_case_against_a_c_alternative
  26. C (programming language) Alternatives
    https://alternativeto.net/software/c-programming-language-/
  27. Seriál Programovací jazyk Go
    https://www.root.cz/seria­ly/programovaci-jazyk-go/
  28. Is C3 the Underdog That Will Overtake Zig and Odin?
    https://bitshifters.cc/2025/05/22/c3-c-tradition.html
  29. „Hello, World!“ program
    https://en.wikipedia.org/wi­ki/%22Hello%2C_World!%22_pro­gram
  30. The C Programming Language
    https://en.wikipedia.org/wi­ki/The_C_Programming_Langu­age
Neutrální ikona do widgetu na odběr článků ze seriálů

Zajímá vás toto téma? Chcete se o něm dozvědět víc?

Objednejte si upozornění na nově vydané články do vašeho mailu. Žádný článek vám tak neuteče.


Autor článku

Vystudoval VUT FIT a v současné době pracuje na projektech vytvářených v jazycích Python a Go.