Obsah
1. Funkce v programovacím jazyku C3
2. Kontroly prováděné překladačem jazyka C3
4. Parametry bez výchozí hodnoty musí předcházet parametry s výchozí hodnotou
5. Explicitní uvedení jmen parametrů při volání funkce
6. Pojmenování parametrů s výchozí hodnotou při volání funkce
7. Funkce s proměnným počtem parametrů
8. Realizace funkce pro výpočet součtu všech předaných hodnot
9. Předání obsahu pole do funkce s proměnným počtem parametrů
10. Pořadí předávání parametrů do funkce s proměnným počtem parametrů
11. Funkce vracející hodnotu typu Optional
13. Kontrakty v definici funkce
14. Kontrakt určující podmínku pro hodnotu parametru
15. Složitější příklad: nepřímé volání funkce s definovaným kontraktem
16. Předávání referencí (ukazatelů) do funkcí
17. Parametry označené [&out] a [&in]
18. Předávání ukazatelů typu void * do volané funkce
19. Repositář s demonstračními příklady
1. Funkce v programovacím jazyku C3
Jednou z nejdůležitějších koncepcí (nejenom) v jazyku C3 je koncept funkcí. Začneme běžnými pojmenovanými funkcemi, ovšem dostaneme se i k anonymním funkcím a metodám (což jsou funkce navázané na konkrétní datové typy). V jazyku C3 jsou funkce deklarovány s využitím klíčového slova fn, za kterým následuje typ návratové hodnoty funkce, jméno funkce a seznam typů+jmen argumentů funkce umístěný do kulatých závorek. Deklarace funkcí je tedy možné ve zdrojovém kódu velmi snadno nalézt, což do jisté míry pomáhá i překladači (dokáže jednoznačně odlišit začátek deklarace funkce od deklarace proměnné).
V dnešním prvním demonstračním příkladu je deklarována dvojice funkcí:
module functions;
import std::io;
fn int add(int a, int b)
{
return a+b;
}
fn void main()
{
io::printf("%d+%d=%d\n", 1, 2, add(1, 2));
}
Povšimněte si, že funkce bez parametrů má prázdné kulaté závorky. Původní „céčkový“ styl deklarace funkce bez parametrů není podporován. To si můžeme velmi snadno ověřit:
module functions;
import std::io;
fn int add(int a, int b)
{
return a+b;
}
fn void main(void)
{
io::printf("%d+%d=%d\n", 1, 2, add(1, 2));
}
Překlad tohoto zdrojového kódu skončí chybou:
6: return a+b;
7: }
8:
9: fn void main(void)
^^^^
(/home/ptisnovs/src/c3-examples/c3-functions/1.c3:9:14) Error: C-style
'foo(void)' style argument declarations are not valid, please remove 'void'.
2. Kontroly prováděné překladačem jazyka C3
Překladač jazyka C3 pochopitelně při volání funkcí (resp. při zápisu volání funkcí) provádí kontroly, které zjišťují, zda je použit správný počet parametrů, jestli mají parametry korektní typ, zda je splněn kontrakt (viz další text) atd. Opět si to můžeme vyzkoušet:
module functions;
import std::io;
fn int add(int a, int b)
{
return a+b;
}
fn void main()
{
add(1, 2);
add(1);
add(1, 2, 3);
add(1.1, 2.2);
add(5000000000, 5000000000);
}
Funkce add je několikrát volána se špatným počtem a/nebo typem parametrů, což překladač odhalí a vypíše poměrně dobře pochopitelná chybová hlášení:
9: fn void main()
10: {
11: add(1, 2);
12: add(1);
^
(/home/ptisnovs/src/c3-examples/c3-functions/02_check_arguments.c3:12:9) Error:
1 more argument was expected after this one, did you forget it?
1: module functions;
2: import std::io;
3:
4: fn int add(int a, int b)
^^^
(/home/ptisnovs/src/c3-examples/c3-functions/02_check_arguments.c3:4:8) Note:
The definition was here.
10: {
11: add(1, 2);
12: add(1);
13: add(1, 2, 3);
^
(/home/ptisnovs/src/c3-examples/c3-functions/02_check_arguments.c3:13:15)
Error: This argument would exceed the number of parameters, did you add too
many arguments?
1: module functions;
2: import std::io;
3:
4: fn int add(int a, int b)
^^^
(/home/ptisnovs/src/c3-examples/c3-functions/02_check_arguments.c3:4:8) Note: The definition was here.
12: add(1);
13: add(1, 2, 3);
14:
15: add(1.1, 2.2);
^^^
(/home/ptisnovs/src/c3-examples/c3-functions/02_check_arguments.c3:15:9) Error:
'double' cannot implicitly be converted to 'int', but you may use a cast.
13: add(1, 2, 3);
14:
15: add(1.1, 2.2);
16: add(5000000000, 5000000000);
^^^^^^^^^^
(/home/ptisnovs/src/c3-examples/c3-functions/02_check_arguments.c3:16:9) Error:
The value '5000000000' is out of range for 'int', so you need an explicit cast
to truncate the value.
Kontrolováno jsou i návratové typy:
module functions;
import std::io;
fn int add(int a, int b)
{
return a+b;
}
fn void main()
{
bool x;
x = add(1, 2);
}
Výsledek:
10: {
11: bool x;
12:
13: x = add(1, 2);
^^^^^^^^^
(/home/ptisnovs/src/c3-examples/c3-functions/18_check_return_type.c3:13:9)
Error: 'int' cannot implicitly be converted to 'bool', but you may use a cast.
A pochopitelně se kontroluje i počet parametrů vracených z funkce:
module functions;
import std::io;
fn int add(int a, int b)
{
}
fn void foo(int a, int b)
{
return a+b;
}
fn void main()
{
}
Obě funkce add i foo vrací nesprávný počet hodnot, což překladač opět odhalí:
1: module functions;
2: import std::io;
3:
4: fn int add(int a, int b)
^^^
(/home/ptisnovs/src/c3-examples/c3-functions/19_check_return_values.c3:4:8)
Error: Missing return statement at the end of the function.
7:
8: fn void foo(int a, int b)
9: {
10: return a+b;
^^^
(/home/ptisnovs/src/c3-examples/c3-functions/19_check_return_values.c3:10:12)
Error: 'int' cannot implicitly be converted to 'void', but you may use a cast.
3. Výchozí hodnoty parametrů
U funkcí lze definovat i výchozí hodnoty parametrů. V takovém případě není nutné při volání funkce předávat novou hodnotu, protože se použije výchozí hodnota. Příklad s výchozí hodnotou posledního parametru b:
module functions;
import std::io;
fn int add(int a, int b=0)
{
return a+b;
}
fn void main()
{
io::printf("%d+%d=%d\n", 1, 0, add(1));
io::printf("%d+%d=%d\n", 1, 2, add(1, 2));
}
Výsledky:
1+0=1 1+2=3
V další variantě mají oba parametry funkce add nastavenou výchozí hodnotu:
module functions;
import std::io;
fn int add(int a=0, int b=0)
{
return a+b;
}
fn void main()
{
io::printf("%d+%d=%d\n", 0, 0, add());
io::printf("%d+%d=%d\n", 1, 0, add(1));
io::printf("%d+%d=%d\n", 1, 2, add(1, 2));
}
To je opět zcela korektní a volání funkce bez předání parametrů, s předáním jednoho parametru i s předáním obou parametrů bude počítat hodnoty podle očekávání:
0+0=0 1+0=1 1+2=3
4. Parametry bez výchozí hodnoty musí předcházet parametry s výchozí hodnotou
Podobně, jako je tomu i u dalších programovacích jazyků, které podporují parametry s výchozí hodnotou, musí být i v jazyku C3 tyto parametry uvedeny na konci seznamu parametrů. Pokusme se tedy v definici (hlavičce) funkce nastavit výchozí hodnotu prvního parametru, ovšem nikoli parametru druhého:
module functions;
import std::io;
fn int add(int a=0, int b)
{
return a+b;
}
fn void main()
{
io::printf("%d+%d=%d\n", 1, 0, add(1));
io::printf("%d+%d=%d\n", 1, 2, add(1, 2));
}
Překladač programovacího jazyka C3 v tomto případě ohlásí chybu, ovšem nikoli v definici funkce, ale až při jejím volání:
8:
9: fn void main()
10: {
11: io::printf("%d+%d=%d\n", 1, 0, add(1));
^
(/home/ptisnovs/src/c3-examples/c3-functions/05_default_arguments.c3:11:40)
Error: 1 more argument was expected after this one, did you forget it?
1: module functions;
2: import std::io;
3:
4: fn int add(int a=0, int b)
^^^
(/home/ptisnovs/src/c3-examples/c3-functions/05_default_arguments.c3:4:8) Note: The definition was here.
5. Explicitní uvedení jmen parametrů při volání funkce
Při volání funkcí s běžnými (pozičními) parametry je ve skutečnosti možné tyto parametry explicitně pojmenovat, což však neumožní změnit jejich pořadí! Pochopitelně je však nutné při volání funkce tyto parametry uvést i se svým jménem. V některých programovacích jazycích se používá tento zápis:
volaná_funkce(foo=hodnota, bar=hodnota, baz=hodnota)
V jazyku C3 je zápis nepatrně odlišný:
volaná_funkce(foo:hodnota, bar:hodnota, baz:hodnota);
Příklad použití pro funkci, ve které záleží na pořadí předaných parametrů:
module functions;
import std::io;
fn int div(int a, int b)
{
return a/b;
}
fn void main()
{
io::printf("%d/%d=%d\n", 10, 2, div(a:10, b:2));
io::printf("%d/%d=%d\n", 10, 3, div(a:10, b:3));
}
Výsledek:
10/2=5 10/3=3
Předání parametrů v jiném pořadí však není v C3 povoleno:
module functions;
import std::io;
fn int div(int a, int b)
{
return a/b;
}
fn void main()
{
io::printf("%d/%d=%d\n", 10, 2, div(b:2, a:10));
io::printf("%d/%d=%d\n", 10, 3, div(b:3, a:10));
}
Výsledkem bude informace o dvou chybách nalezených ve zdrojovém kódu:
8:
9: fn void main()
10: {
11: io::printf("%d/%d=%d\n", 10, 2, div(b:2, a:10));
^^^^
(/home/ptisnovs/src/c3-examples/c3-functions/07_named_arguments.c3:11:46)
Error: Named arguments must always be declared in order.
8:
9: fn void main()
10: {
11: io::printf("%d/%d=%d\n", 10, 2, div(b:2, a:10));
^^^
(/home/ptisnovs/src/c3-examples/c3-functions/07_named_arguments.c3:11:41) Note:
Place it before this argument.
9: fn void main()
10: {
11: io::printf("%d/%d=%d\n", 10, 2, div(b:2, a:10));
12: io::printf("%d/%d=%d\n", 10, 3, div(b:3, a:10));
^^^^
(/home/ptisnovs/src/c3-examples/c3-functions/07_named_arguments.c3:12:46)
Error: Named arguments must always be declared in order.
9: fn void main()
10: {
11: io::printf("%d/%d=%d\n", 10, 2, div(b:2, a:10));
12: io::printf("%d/%d=%d\n", 10, 3, div(b:3, a:10));
^^^
(/home/ptisnovs/src/c3-examples/c3-functions/07_named_arguments.c3:12:41) Note:
Place it before this argument.
6. Pojmenování parametrů s výchozí hodnotou při volání funkce
Pojmenovat je možné i parametry s výchozí hodnotou, což je kombinace obou přístupů popsaných v předchozích dvou kapitolách:
module functions;
import std::io;
fn int div(int a=1, int b=1)
{
return a/b;
}
fn void main()
{
io::printf("%d/%d=%d\n", 1, 1, div());
io::printf("%d/%d=%d\n", 10, 1, div(a:10));
io::printf("%d/%d=%d\n", 10, 2, div(a:10, b:2));
io::printf("%d/%d=%d\n", 10, 3, div(a:10, b:3));
}
Vypočtené a zobrazené výsledky by měly vypadat následovně:
1/1=1 10/1=10 10/2=5 10/3=3
Ovšem opět není možné pořadí parametrů při volání funkce prohodit:
module functions;
import std::io;
fn int div(int a=1, int b=1)
{
return a/b;
}
fn void main()
{
io::printf("%d/%d=%d\n", 10, 2, div(b:2, a:10));
}
Výsledek:
8:
9: fn void main()
10: {
11: io::printf("%d/%d=%d\n", 10, 2, div(b:2, a:10));
^^^^
(/home/ptisnovs/src/c3-examples/c3-functions/1.c3:11:46) Error: Named arguments
must always be declared in order.
8:
9: fn void main()
10: {
11: io::printf("%d/%d=%d\n", 10, 2, div(b:2, a:10));
^^^
(/home/ptisnovs/src/c3-examples/c3-functions/1.c3:11:41) Note: Place it before
this argument.
7. Funkce s proměnným počtem parametrů
V některých případech je užitečné mít možnost vytvoření funkce, která bude mít proměnný počet parametrů. Takové funkce jsou podporovány i původním jazykem C, i když práce s proměnným počtem parametrů je zde poměrně komplikovaná. Naproti tomu v jazyku C3 se s takovými funkcemi pracuje velmi snadno a při zpracování většího množství parametrů ani nemusí docházet k chybám (přístup k neexistujícímu parametru atd).
V hlavičce funkce akceptující proměnný (a předem neznámý) počet parametrů používá zápis:
typ... jméno
Například:
fn int sum(int... args) ... ... ...
V těle funkce se s args pracuje stejně, jako by se jednalo o řez (slice). To znamená, že nemusíme předávat ani počet skutečně předaných argumentů ani používat makra typu va_start (jako je tomu v jazyku C).
8. Realizace funkce pro výpočet součtu všech předaných hodnot
Pokusme se nyní o implementaci funkce, která po svém zavolání provede součet všech předaných celočíselných hodnot, přičemž není dopředu známo, kolik těchto hodnot bude ve skutečnosti předáno. Interně je součet hodnot realizován programovou smyčkou foreach, se kterou jsme se již v tomto seriálu seznámili. Povšimněte si, jak jednoduše a čitelně je celý výpočet realizován:
module functions;
import std::io;
fn int sum(int... args)
{
int sum = 0;
foreach (arg : args) {
sum += arg;
}
return sum;
}
fn void main()
{
io::printf("%d\n", sum());
io::printf("%d\n", sum(1));
io::printf("%d\n", sum(1, 2));
io::printf("%d\n", sum(1, 2, 3));
}
Funkce sum je postupně volána bez parametrů, s jedním parametrem, se dvěma a nakonec se třemi parametry:
0 1 3 6
9. Předání obsahu pole do funkce s proměnným počtem parametrů
Do funkce akceptující proměnný počet parametrů je možné předat i obsah celého pole. Používá se přitom zápis se třemi tečkami. Po zavolání funkce (tedy v jejím těle) se řízení programu chová tak, jakoby byla funkce zavolána s tolika parametry, kolik je prvků předaného pole:
int[10] values = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
io::printf("%d\n", sum(...values));
module functions;
import std::io;
fn int sum(int... args)
{
int sum = 0;
foreach (arg : args) {
sum += arg;
}
return sum;
}
fn void main()
{
int[10] values = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
io::printf("%d\n", sum());
io::printf("%d\n", sum(1));
io::printf("%d\n", sum(1, 2));
io::printf("%d\n", sum(1, 2, 3));
io::printf("%d\n", sum(...values));
}
Opět si zkontrolujme, jaké výsledky budou vypočteny a zobrazeny:
0 1 3 6 55
10. Pořadí předávání parametrů do funkce s proměnným počtem parametrů
V současné verzi programovacího jazyka C můžeme narazit na následující past, například u funkce s touto hlavičkou:
fn int sum(int... args, int multiplier) ... ... ...
Problém spočívá v tom, že při volání funkce tímto způsobem (pouhým předáním pozičních parametrů bez jejich pojmenování) nebude nikdy parametr multiplier naplněn:
io::printf("%d\n", sum());
io::printf("%d\n", sum(1));
io::printf("%d\n", sum(1, 2));
io::printf("%d\n", sum(1, 2, 3));
io::printf("%d\n", sum(...values));
To ve svém důsledku vede k tomu, že současná verze překladače jazyka C3 sice program přeloží, ale po jeho spuštění dojde k přístupu do chráněné paměti a tím pádem k segfaultu:
module functions;
import std::io;
fn int sum(int... args, int multiplier)
{
int sum = 0;
foreach (arg : args) {
sum += arg;
}
return sum * multiplier;
}
fn void main()
{
int[10] values = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
io::printf("%d\n", sum());
io::printf("%d\n", sum(1));
io::printf("%d\n", sum(1, 2));
io::printf("%d\n", sum(1, 2, 3));
io::printf("%d\n", sum(...values));
}
Oprava spočívá buď v prohození obou parametrů tak, aby args byl na konci, nebo v explicitním pojmenování parametrů při volání funkce:
io::printf("%d\n", sum(multiplier: 10));
io::printf("%d\n", sum(1, multiplier: 10));
io::printf("%d\n", sum(1, 2, multiplier: 10));
io::printf("%d\n", sum(1, 2, 3, multiplier: 10));
io::printf("%d\n", sum(...values, multiplier: 10));
Můžeme si to ostatně velmi snadno otestovat:
module functions;
import std::io;
fn int sum(int... args, int multiplier)
{
int sum = 0;
foreach (arg : args) {
sum += arg;
}
return sum * multiplier;
}
fn void main()
{
int[10] values = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
io::printf("%d\n", sum(multiplier: 10));
io::printf("%d\n", sum(1, multiplier: 10));
io::printf("%d\n", sum(1, 2, multiplier: 10));
io::printf("%d\n", sum(1, 2, 3, multiplier: 10));
io::printf("%d\n", sum(...values, multiplier: 10));
}
Tento program již bude bez problémů přeložitelný i spustitelný:
0 10 30 60 550
11. Funkce vracející hodnotu typu Optional
Připomeňme si, že v programovacím jazyku C3 je možné pracovat s hodnotami typu Optional. Ty obsahují buď konkrétní hodnotu (například celé číslo), nebo informaci o chybě resp. o neexistující hodnotě. Samozřejmě nám nic nebrání v deklaraci funkce, jejíž návratový typ bude právě Optional. Příkladem může být funkce realizující celočíselné dělení, která (jak asi správně předpokládáte) není dobře definována pro dělitel nastavený na nulu. V takovém případě by funkce měla vracet informaci o chybě a tudíž právě zde využijeme typ Optional. Návratovým typem tedy nebude pouhé int ale int?:
module functions;
import std::io;
faultdef ZERO_INPUT;
fn int? div(int a=1, int b=1)
{
if (b==0) {
return ZERO_INPUT?;
}
return a/b;
}
fn void main()
{
(void)io::printf("%d/%d=%d\n", 1, 1, div());
(void)io::printf("%d/%d=%d\n", 10, 1, div(a:10));
(void)io::printf("%d/%d=%d\n", 10, 2, div(a:10, b:2));
(void)io::printf("%d/%d=%d\n", 10, 3, div(a:10, b:3));
(void)io::printf("%d/%d=%d\n", 10, 0, div(a:10, b:0));
}
Ověřme si, jak se bude tento příklad, který vlastně vůbec nepočítá s chybovou hodnotou, chovat v runtime:
1/1=1 10/1=10 10/2=5 10/3=3
To je zajímavé, protože poslední příkaz io::printf nebyl vůbec spuštěn. Je to způsobeno tím, že je před něj zapsána operace přetypování na void. Chování jazyka C3 je následující – pokud nějaká volaná funkce vrací typ Optional a namísto (obalené) hodnoty je vrácena chyba, je vyhodnocení přerušeno.
Bez přetypování nebude možné příklad vůbec přeložit:
16: io::printf("%d/%d=%d\n", 1, 1, div());
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
(/home/ptisnovs/src/c3-examples/c3-functions/13_optional.c3:16:5) Error:
The result of this call is optional due to its argument(s). This
optional result may not be implicitly discarded. Please assign it to a
variable, ignore it with '(void)', rethrow with '!' or panic with '!!'.
14: fn void main()
15: {
16: io::printf("%d/%d=%d\n", 1, 1, div());
17: io::printf("%d/%d=%d\n", 10, 1, div(a:10));
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
(/home/ptisnovs/src/c3-examples/c3-functions/13_optional.c3:17:5) Error:
The result of this call is optional due to its argument(s). This
optional result may not be implicitly discarded. Please assign it to a
variable, ignore it with '(void)', rethrow with '!' or panic with '!!'.
12. Využití operátoru ??
V souvislosti s funkcemi, které vrací hodnoty typu Optional, se můžeme setkat s použitím speciálního operátoru zapisovaného dvojicí znaků ??. Tento operátor umožňuje řetězit větší množství podvýrazů, z nichž každý je typu Optional. Pokud je levý podvýraz vyhodnocen jako normální hodnota, je výsledkem zápisu levý podvýraz ?? pravý podvýraz přímo levý podvýraz. Naopak, jestliže je levý podvýraz vyhodnocen jako chybějící hodnota a/nebo chyba, je výsledkem zápisu levý podvýraz ?? pravý podvýraz podvýraz pravý.
To nám umožňuje (například) reagovat na chybu při dělení tak, že tuto chybu nahradíme hodnotou –1. Zápis je poměrně elegantní:
result = div(10, 1) ?? -1;
Vyzkoušejme si to v praxi, nyní opět s funkcí div upravenou do takové podoby, že v případě, kdy by se mělo dělit nulou, vrací chybu:
module functions;
import std::io;
faultdef ZERO_INPUT;
fn int? div(int a=1, int b=1)
{
if (b==0) {
return ZERO_INPUT?;
}
return a/b;
}
fn void main()
{
int? result;
result = div(10, 1) ?? -1;
(void)io::printf("%d/%d=%d\n", 10, 1, result);
result = div(10, 0) ?? -1;
(void)io::printf("%d/%d=%d\n", 10, 0, result);
}
Takto budou vypadat výsledky:
10/1=10 10/0=-1
13. Kontrakty v definici funkce
V programovacím jazyku C3 nalezneme ještě jednu zajímavou konstrukci. Jedná se o takzvané kontrakty, s jejichž využitím je možné překladači předat další dodatečné informace týkající se buď parametrů funkce, nebo její návratové hodnoty. Kontrakty se tedy rozdělují na specifikaci podmínek, které je nutné splnit před voláním (resp. v rámci volání) funkce a na specifikaci podmínek, které budou platit po zavolání funkce. Striktně řečeno se nejedná o součást typového systému, ale pouze o určitá doporučení pro překladač, který se může, ale taky nemusí těmito podmínkami řídit (někdy je totiž tok programu tak složitý, že se překladač „ztratí“ a neumožní kontrolu všech zapsaných podmínek). V následujících kapitolách si ukážeme základní způsoby použití kontraktů, ovšem ve skutečnosti mohou být kontrakty i složitější (ostatně se k těm složitějším ještě vrátíme).
14. Kontrakt určující podmínku pro hodnotu parametru
Podívejme se nyní na velmi jednoduchý příklad kontraktu. S funkcí div, která dokáže vypočítat celočíselný podíl, jsme se již setkali. Nyní tuto funkci upravíme do odlišné podoby – s využitím kontraktu budeme specifikovat, že druhý parametr b nesmí být nulový. Pokud se funkce volá s předáním konstant, dokáže tento kontrakt kontrolovat již překladač:
module functions;
import std::io;
<*
@require b != 0
*>
fn int div(int a, int b)
{
return a/b;
}
fn void main()
{
io::printf("%d/%d=%d\n", 10, 2, div(10, 2));
io::printf("%d/%d=%d\n", 10, 3, div(10, 3));
io::printf("%d/%d=%d\n", 10, 0, div(10, 0));
}
Pokus o překlad tohoto zdrojového kódu dopadne následovně:
13: {
14: io::printf("%d/%d=%d\n", 10, 2, div(10, 2));
15: io::printf("%d/%d=%d\n", 10, 3, div(10, 3));
16: io::printf("%d/%d=%d\n", 10, 0, div(10, 0));
^^^^^^^^^^
(/home/ptisnovs/src/c3-examples/c3-functions/15_contract.c3:16:37)
Error: @require "b != 0" violated.
Naproti tomu v následujícím demonstračním příkladu již samotný překladač kontrakt nezajistí – to ponechá až na runtime systému:
module functions;
import std::io;
<*
@require b != 0
*>
fn int div(int a, int b)
{
return a/b;
}
fn void main()
{
for (int i=10; i>=0; i--) {
io::printf("%d/%d=%d\n", 10, i, div(10, i));
}
}
Problém s předáním nulové hodnoty do parametru b sice stále bude nalezen, ale až v runtime, nikoli při překladu:
10/10=1 10/9=1 10/8=1 10/7=1 10/6=1 10/5=2 10/4=2 10/3=3 10/2=5 10/1=10 ERROR: '@require "b != 0" violated.' in std.core.builtin.default_panic (/home/ptisnovs/xy/c3c/build/lib/std/core/builtin.c3:175) [/home/ptisnovs/src/c3-examples/c3-functions/functions] in functions.main (/home/ptisnovs/src/c3-examples/c3-functions/24_contract.c3:15) [/home/ptisnovs/src/c3-examples/c3-functions/functions] in @main_to_void_main (/home/ptisnovs/xy/c3c/build/lib/std/core/private/main_stub.c3:18) [/home/ptisnovs/src/c3-examples/c3-functions/functions] [inline] in main (/home/ptisnovs/src/c3-examples/c3-functions/24_contract.c3:12) [/home/ptisnovs/src/c3-examples/c3-functions/functions] in __libc_start_call_main (source unavailable) [/lib64/libc.so.6] in __libc_start_main_alias_2 (source unavailable) [/lib64/libc.so.6] in _start (source unavailable) [/home/ptisnovs/src/c3-examples/c3-functions/functions] Program interrupted by signal 4.
15. Složitější příklad: nepřímé volání funkce s definovaným kontraktem
Současná verze překladače programovacího jazyka C3 prozatím nedokáže spolehlivě v čase překladu detekovat problém v následujícím demonstračním příkladu. Zde opět voláme funkci div(10, 0) (tedy snažíme se dělit nulou), ovšem div voláme nepřímo přes jinou funkci call_div. Teoreticky by měl překladač tento stav detekovat a zobrazit chybové hlášení již při překladu, ve skutečnosti se tak však v tomto případě stane až v runtime:
module functions;
import std::io;
<*
@require b != 0
*>
fn int div(int a, int b)
{
return a/b;
}
fn int call_div(int a, int b)
{
return div(a, b);
}
fn void main()
{
io::printf("%d/%d=%d\n", 10, 2, call_div(10, 2));
io::printf("%d/%d=%d\n", 10, 3, call_div(10, 3));
io::printf("%d/%d=%d\n", 10, 0, call_div(10, 0));
}
A takto vypadá pokus o překlad a spuštění příkladu – chyba je vyhozena až v případě, že se skutečně dělí nulou:
Launching ./functions 10/2=5 10/3=3 ERROR: '@require "b != 0" violated.' in std.core.builtin.default_panic (/home/ptisnovs/xy/c3c/build/lib/std/core/builtin.c3:175) [/home/ptisnovs/src/c3-examples/c3-functions/functions] in functions.call_div (/home/ptisnovs/src/c3-examples/c3-functions/16_contract.c3:14) [/home/ptisnovs/src/c3-examples/c3-functions/functions] in functions.main (/home/ptisnovs/src/c3-examples/c3-functions/16_contract.c3:21) [/home/ptisnovs/src/c3-examples/c3-functions/functions] in @main_to_void_main (/home/ptisnovs/xy/c3c/build/lib/std/core/private/main_stub.c3:18) [/home/ptisnovs/src/c3-examples/c3-functions/functions] [inline] in main (/home/ptisnovs/src/c3-examples/c3-functions/16_contract.c3:17) [/home/ptisnovs/src/c3-examples/c3-functions/functions] in __libc_start_call_main (source unavailable) [/lib64/libc.so.6] in __libc_start_main_alias_2 (source unavailable) [/lib64/libc.so.6] in _start (source unavailable) [/home/ptisnovs/src/c3-examples/c3-functions/functions] Program interrupted by signal 4.
16. Předávání referencí (ukazatelů) do funkcí
Typový systém programovacího jazyka C3 plně podporuje ukazatele, takže asi nebude překvapením, že do funkcí lze předávat i parametry typu ukazatel na T. To mj. umožňuje změnu hodnot přímo ve volané funkci. Ukažme si typický školní příklad funkce, která nastaví hodnotu, na kterou je předaný ukazatel:
module functions;
import std::io;
fn void set(int *p, int new_value)
{
*p=new_value;
}
fn void main()
{
int i = 0;
io::printf("%d\n", i);
set(&i, 42);
io::printf("%d\n", i);
}
Po překladu a spuštění by se měly zobrazit následující dvě hodnoty naznačující, že se skutečně obsah proměnné i změnil, a to přes ukazatel:
0 42
17. Parametry označené [&out] a [&in]
V souvislosti s předáváním ukazatelů do funkcí je možné pomocí kontraktu naznačit, zda je hodnota předávaná ukazatelem (referencí) měnitelná uvnitř funkce či nikoli. Tento nebylo nutné u „běžných“ parametrů řešit, protože ty se předávají hodnotou (a tedy se vlastně vždy kopírují), ovšem ukazatele jako parametry slouží ke dvěma rozdílným účelům:
- Optimalizace – předání odkazy na velký blok paměti bez nutnosti jeho kopie, i když se ve funkci tento blok nemodifikuje
- Předání odkazem, tj. očekává se, že se hodnota bude přes ukazatel skutečně měnit
Rozlišení mezi těmito dvěma scénáři zajišťuje právě vhodně zapsaný kontrakt. Příkladem může být označení parametru typu ukazatel jako „výstupního“ parametru – hodnotu bude možné přes ukazatel modifikovat:
module functions;
import std::io;
<*
@param [&out] p
*>
fn void set(int *p, int new_value)
{
*p=new_value;
}
fn void main()
{
int i = 0;
io::printf("%d\n", i);
set(&i, 42);
io::printf("%d\n", i);
}
Tento demonstrační příklad lze bez problémů přeložit a spustit:
0 42
Ovšem taktéž můžeme přes kontrakt označit parametr typu ukazatel za vstupní, tj. referencovanou hodnotu nebude možné přes tento ukazatel modifikovat:
module functions;
import std::io;
<*
@param [&in] p
*>
fn void set(int *p, int new_value)
{
*p=new_value;
}
fn void main()
{
int i = 0;
io::printf("%d\n", i);
set(&i, 42);
io::printf("%d\n", i);
}
Pokus o zápis je detekován překladačem a zdrojový kód není možné přeložit:
6: *>
7: fn void set(int *p, int new_value)
8: {
9: *p=new_value;
^
(/home/ptisnovs/src/c3-examples/c3-functions/22_in_out_params.c3:9:6) Error:
'in' parameters may not be assigned to.
18. Předávání ukazatelů typu void * do volané funkce
V programovacím jazyku C3 jsou podporovány i de facto beztypové ukazatele, které jsou typu void *. Při provádění dereference je však nutné provést explicitní přetypování, například tak, jak je to ukázáno v dnešním posledním demonstračním příkladu (což není moc pěkný zápis, na druhou stranu se však beztypové ukazatele v jazyce C3 nepoužívají příliš často):
module functions;
import std::io;
fn void set(void *p, int new_value)
{
*(int*)p=new_value;
}
fn void main()
{
int i = 0;
io::printf("%d\n", i);
set(&i, 42);
io::printf("%d\n", i);
}
Po překladu a spuštění tohoto demonstračního příkladu by se měly zobrazit stejné zprávy, jako tomu bylo v šestnácté kapitole:
0 42
19. Repositář s demonstračními příklady
Demonstrační příklady vytvořené pro nejnovější verzi programovacího jazyka C3 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).
Demonstrační příklady z prvního článku o programovacím jazyku C3:
| # | 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 |
Demonstrační příklady ze druhého článku o jazyku C3:
| # | Příklad | Stručný popis | Adresa |
|---|---|---|---|
| 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 |
Demonstrační příklady použité ve třetím článku o jazyku C3:
Demonstrační příklady ze čtvrtého o jazyku C3:
| # | Příklad | Stručný popis | Adresa |
|---|---|---|---|
| 57 | 01_program_stub.c3 | struktura programu s uvedeným plným jménem modulu | https://github.com/tisnik/c3-examples/blob/master/c3-control-flow/01_program_stub.c3 |
| 58 | 02_if.c3 | nejjednodušší forma rozvětvení založené na konstrukci if | https://github.com/tisnik/c3-examples/blob/master/c3-control-flow/02_if.c3 |
| 59 | 03_if_else.c3 | plné rozvětvení realizované konstrukcí if-else | https://github.com/tisnik/c3-examples/blob/master/c3-control-flow/03_if_else.c3 |
| 60 | 04_improper_if.c3 | nekorektní způsob zápisu programové konstrukce if-else (porovnání s jazykem C) | https://github.com/tisnik/c3-examples/blob/master/c3-control-flow/04_improper_if.c3 |
| 61 | 05_improper_if.c3 | nekorektní způsob zápisu programové konstrukce if-else (porovnání s jazykem C) | https://github.com/tisnik/c3-examples/blob/master/c3-control-flow/05_improper_if.c3 |
| 62 | 06_if_else_if.c3 | složitější rozvětvení založené na programové konstrukci if-else if-else | https://github.com/tisnik/c3-examples/blob/master/c3-control-flow/06_if_else_if.c3 |
| 63 | 07_switch_basic.c3 | základní forma vícenásobného rozvětvení založeného na konstrukci switch-case | https://github.com/tisnik/c3-examples/blob/master/c3-control-flow/07_switch_basic.c3 |
| 64 | 08_switch_basic.c3 | větší množství podmínek a programová konstrukce switch-case | https://github.com/tisnik/c3-examples/blob/master/c3-control-flow/08_switch_basic.c3 |
| 65 | 09_switch_condition.c3 | podmínky zapsané ve větvích programové konstrukci switch-case vyhodnocované v čase běhu procesu | https://github.com/tisnik/c3-examples/blob/master/c3-control-flow/09_switch_condition.c3 |
| 66 | 10_switch_true.c3 | konstrukce switch-case bez uvedeného výrazu za klíčovým slovem switch | https://github.com/tisnik/c3-examples/blob/master/c3-control-flow/10_switch_true.c3 |
| 67 | 11_switch_break.c3 | zápis prázdné větve default v programové konstrukci switch-case | https://github.com/tisnik/c3-examples/blob/master/c3-control-flow/11_switch_break.c3 |
| 68 | 12_switch_nextcase.c3 | pokračování ve vykonávání konstrukce switch-case vynucené klíčovým slovem nextcase | https://github.com/tisnik/c3-examples/blob/master/c3-control-flow/12_switch_nextcase.c3 |
| 69 | 13_for_loop.c3 | základní forma programové smyčky realizované klíčovým slovem for | https://github.com/tisnik/c3-examples/blob/master/c3-control-flow/13_for_loop.c3 |
| 70 | 14_foreach_loop.c3 | základní forma programové smyčky typu for-each | https://github.com/tisnik/c3-examples/blob/master/c3-control-flow/14_foreach_loop.c3 |
| 71 | 15_foreach_loop.c3 | programová smyčka for-each vracející index prvku i hodnotu prvku | https://github.com/tisnik/c3-examples/blob/master/c3-control-flow/15_foreach_loop.c3 |
| 72 | 16_foreach_loop.c3 | modifikace obsahu pole v programové smyčce for-each | https://github.com/tisnik/c3-examples/blob/master/c3-control-flow/16_foreach_loop.c3 |
| 73 | 17_foreach_loop.c3 | pokus o modifikaci obsahu procházeného pole | https://github.com/tisnik/c3-examples/blob/master/c3-control-flow/17_foreach_loop.c3 |
| 74 | 18_foreach_loop.c3 | modifikace procházeného pole přes ukazatel na prvek | https://github.com/tisnik/c3-examples/blob/master/c3-control-flow/18_foreach_loop.c3 |
| 75 | 19_foreach_r_loop.c3 | programová smyčka for-each, ve které se sekvencí prochází v opačném pořadí | https://github.com/tisnik/c3-examples/blob/master/c3-control-flow/19_foreach_r_loop.c3 |
| 76 | 20_while_loop.c3 | základní forma programové smyčky typu while | https://github.com/tisnik/c3-examples/blob/master/c3-control-flow/20_while_loop.c3 |
| 77 | 21_while_loop2.c3 | programová smyčka typu while s konstrukcí break | https://github.com/tisnik/c3-examples/blob/master/c3-control-flow/21_while_loop2.c3 |
| 78 | 22_nested_loops.c3 | realizace vnořených programových smyček | https://github.com/tisnik/c3-examples/blob/master/c3-control-flow/22_nested_loops.c3 |
| 79 | 23_break.c3 | vnořené programové smyčky a příkaz break: ukončení vnitřní smyčky | https://github.com/tisnik/c3-examples/blob/master/c3-control-flow/23_break.c3 |
| 80 | 24_break.c3 | vnořené programové smyčky a příkaz break: ukončení vnější smyčky | https://github.com/tisnik/c3-examples/blob/master/c3-control-flow/24_break.c3 |
| 81 | 25_break.c3 | vnořené programové smyčky a příkaz break, varianta se smyčkami typu while | https://github.com/tisnik/c3-examples/blob/master/c3-control-flow/25_break.c3 |
Demonstrační příklady z pátého článku o jazyku C3:
A konečně následují odkazy na demonstrační příklady z článku dnešního:
| # | Příklad | Stručný popis | Adresa | |
|---|---|---|---|---|
| 100 | 01_regular_function.c3 | deklarace běžných funkcí v jazyku C3 | https://github.com/tisnik/c3-examples/blob/master/c3-functions/01_regular_function.c3 | |
| 101 | 02_check_arguments.c3 | kontrola parametrů předávaných do funkce překladačem jazyka C3 | https://github.com/tisnik/c3-examples/blob/master/c3-functions/02_check_arguments.c3 | |
| 102 | 03_default_arguments.c3 | funkce s jedním parametrem, který má nastavenou výchozí hodnotu a jedním běžným parametrem (korektní pořadí parametrů) | https://github.com/tisnik/c3-examples/blob/master/c3-functions/03_default_arguments.c3 | |
| 103 | 04_default_arguments.c3 | funkce se všemi parametry s nastavenu výchozí hodnotou | https://github.com/tisnik/c3-examples/blob/master/c3-functions/04_default_arguments.c3 | |
| 104 | 05_default_arguments.c3 | funkce s jedním parametrem, který má nastavenou výchozí hodnotu a jedním běžným parametrem (nekorektní pořadí parametrů) | https://github.com/tisnik/c3-examples/blob/master/c3-functions/05_default_arguments.c3 | |
| 105 | 06_named_arguments.c3 | explicitní uvedení jmen parametrů při volání funkce | https://github.com/tisnik/c3-examples/blob/master/c3-functions/06_named_arguments.c3 | |
| 106 | 07_named_arguments.c3 | explicitní uvedení jmen parametrů při volání funkce | https://github.com/tisnik/c3-examples/blob/master/c3-functions/07_named_arguments.c3 | |
| 107 | 08_named_default_arguments.c3 | pojmenování parametrů s výchozí hodnotou při volání funkce | https://github.com/tisnik/c3-examples/blob/master/c3-functions/08_named_default_arguments.c3 | |
| 108 | 09_sum.c3 | realizace funkce pro výpočet součtu všech předaných hodnot | https://github.com/tisnik/c3-examples/blob/master/c3-functions/09_sum.c3 | |
| 109 | 10_sum.c3 | předání obsahu pole do funkce s proměnným počtem parametrů | https://github.com/tisnik/c3-examples/blob/master/c3-functions/10_sum.c3 | |
| 110 | 11_varargs.c3 | pořadí předávání parametrů do funkce s proměnným počtem parametrů (nekorektní způsob použití) | https://github.com/tisnik/c3-examples/blob/master/c3-functions/11_varargs.c3 | |
| 111 | 12_varargs.c3 | pořadí předávání parametrů do funkce s proměnným počtem parametrů (korektní způsob použití) | https://github.com/tisnik/c3-examples/blob/master/c3-functions/12_varargs.c3 | |
| 112 | 13_optional.c3 | funkce vracející hodnotu typu Optional | https://github.com/tisnik/c3-examples/blob/master/c3-functions/13_optional.c3 | |
| 113 | 14_optional.c3 | využití operátoru ?? | https://github.com/tisnik/c3-examples/blob/master/c3-functions/14_optional.c3 | |
| 114 | 15_contract.c3 | kontrakty uvedené u funkcí | https://github.com/tisnik/c3-examples/blob/master/c3-functions/15_contract.c3 | |
| 115 | 16_contract.c3 | kontrakty uvedené u funkcí | https://github.com/tisnik/c3-examples/blob/master/c3-functions/16_contract.c3 | |
| 116 | 17_c_declaration.c3 | deklarace funkce bez parametrů „céčkovým způsobem“ (nekorektní zápis) | https://github.com/tisnik/c3-examples/blob/master/c3-functions/17_c_declaration.c3 | |
| 117 | 18_check_return_type.c3 | kontrola návratové hodnoty překladačem jazyka C3 | https://github.com/tisnik/c3-examples/blob/master/c3-functions/18_check_return_type.c3 | |
| 118 | 19_check_return_value.c3 | kontrola počtu návratových hodnot překladačem jazyka C3 | https://github.com/tisnik/c3-examples/blob/master/c3-functions/19_check_return_value.c3 | |
| 119 | 20_in_out_params.c3 | předání ukazatelů do volané funkce | https://github.com/tisnik/c3-examples/blob/master/c3-functions/20_in_out_params.c3 | |
| 120 | 21_in_out_params.c3 | označení ukazatelů kontrakty [in] a [out] | https://github.com/tisnik/c3-examples/blob/master/c3-functions/21_in_out_params.c3 | |
| 121 | 22_in_out_params.c3 | označení ukazatelů kontrakty [in] a [out] | https://github.com/tisnik/c3-examples/blob/master/c3-functions/22_in_out_params.c3 | |
| 122 | 23_void_pointer.c3 | předávání ukazatelů typu void * do volané funkce | https://github.com/tisnik/c3-examples/blob/master/c3-functions/23_void_pointer.c3 |
20. Odkazy na Internetu
- Programovací jazyk C3: evoluce, nikoli revoluce
https://www.root.cz/clanky/programovaci-jazyk-c3-evoluce-nikoli-revoluce/ - Programovací jazyk C3: datové typy pro moderní architektury
https://www.root.cz/clanky/programovaci-jazyk-c3-datove-typy-pro-moderni-architektury/ - Programovací jazyk C3: složené datové typy a kontejnery
https://www.root.cz/clanky/programovaci-jazyk-c3-slozene-datove-typy-a-kontejnery/ - 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 - Kontejner (abstraktní datový typ)
https://cs.wikipedia.org/wiki/Kontejner_(abstraktn%C3%AD_datov%C3%BD_typ) - Are arrays not considered containers because they are not based off of a class?
https://stackoverflow.com/questions/37710975/are-arrays-not-considered-containers-because-they-are-not-based-off-of-a-class - Array declaration (C, C++)
https://en.cppreference.com/w/cpp/language/array.html - Understanding the Apple ‘goto fail;’ vulnerability
https://www.blackduck.com/blog/understanding-apple-goto-fail-vulnerability-2.html - Branch (computer science)
https://en.wikipedia.org/wiki/Branch_(computer_science) - Conditional (computer programming)
https://en.wikipedia.org/wiki/Conditional_(computer_programming) - Dangling else
https://en.wikipedia.org/wiki/Dangling_else - Switch statement
https://en.wikipedia.org/wiki/Switch_statement - Compiler correctness
https://en.wikipedia.org/wiki/Compiler_correctness