Obsah
1. Systém maker v programovacím jazyku C3
2. Makra ve vyšších programovacích jazycích
3. Definice a expanze jednoduchého makra
4. Expanze makra pro hodnoty různých datových typů
5. Problematika závorek v klasických céčkovských makrech vs. makra v C3
6. Uzávorkování parametrů makra v céčku
7. Makro expandované ve složitějším výrazu: varianta pro jazyk C3
8. Makro expandované ve složitějším výrazu: varianta pro jazyk C
9. Specifikace datových typů v definici makra
10. Pokus o expanzi makra s předáním parametrů nekorektních typů
11. Makra expandovaná do konstantních výrazů
12. Parametry makra vyhodnocované v době překladu
13. Předání jména proměnné nebo složitějšího výrazu do argumentu začínajícího znakem $
14. Pokus o definici makra, které prohodí obsah dvou proměnných
15. Druhá varianta makra pro prohození obsahu dvou proměnných
16. Potenciálně nebezpečná makra
17. Makro s proměnným počtem argumentů
19. Repositář s demonstračními příklady
1. Systém maker v programovacím jazyku C3
Programovací jazyk C3 patří do stejné niky programovacích jazyků, ve které se nachází i jazyk C. Céčkovské programovací jazyky jsou vybaveny makrosystémem, tj. je v nich možné vytvářet makra, která jsou při svém volání expandována a namísto volání makra se do zdrojového kódu vloží jeho expandovaná podoba. Jak v jazyku C tak i v C++ tato expanze probíhá ještě před vlastním překladem (ten začíná parsingem), což znamená, že při expanzi maker není kontrolována ani syntaxe ani korektnost datových typů; navíc je většinou nutné parametry makra i jeho tělo správně „uzávorkovat“, takže používání maker je relativně nebezpečná operace. V jazyku C3 je situace odlišná, protože v něm lze vytvářet bezpečnější makra (navíc i s volitelnou podporou datových typů); na druhou stranu jsou však k dispozici i složitější konstrukce „nebezpečných“ maker, tj. maker, ve kterých se může měnit tok běhu programu atd. Dnes se seznámíme se základy tohoto systému a porovnáme možnosti C3 s původním céčkem.
2. Makra ve vyšších programovacích jazycích
V programovacích jazycích C, C++, ale například i v m4 se makra používají pro „pouhé“ provádění textových substitucí prováděných typicky v průběhu načítání zdrojových kódů, zatímco makrosystém implementovaný v jazyku C3 je založen na modifikaci AST, což na jednu stranu umožňuje mnohem hlubší zásahy do kódu, na stranu druhou jsou makra bezpečnější. V tomto ohledu má jazyk C3, podobně jako jazyk Rust, poměrně blízko k LISPovským jazykům, v nichž je většinou makrosystém prakticky nedílnou součástí programovacího jazyka, protože jsou v něm realizovány mnohdy i základní programové konstrukce (navíc je LISP homoikonickým jazykem, což situaci dále zjednodušuje). Asi nejtypičtějším příkladem použití maker v LISPu je makro loop použité v Common Lispu (na druhou stranu někteří vývojáři soudí, že podobná makra zbytečně do Common Lispu přidávají imperativní kód, to je ovšem oblast přesahující téma dnešního článku). Některé vlastnosti tohoto makra jsou popsány na stránce http://www.ai.sri.com/pkarp/loop.html. Podobným způsobem se s makry pracuje i v dalších jazycích založených na LISPu; příkladem je Clojure.
V programovacím jazyku C3 se navíc při definici makra a popř. při jeho expanzi provádí kontroly, zda jsou použity korektní datové typy, což je oproti jazykům C/C++ (pouhá textová expanze) další výhoda.
3. Definice a expanze jednoduchého makra
Způsob využití makrosystému programovacího jazyka C3 lze nejlépe vysvětlit na praktických příkladech. Podívejme se například na to, jakým způsobem je možné definovat makro nazvané add, které je určené pro výpočet součtu dvou hodnot. Jedná se o makro, které vrací nějakou hodnotu a proto bude expandováno do formy výrazu. Bude ho tedy možné použít všude tam, kde se očekává výraz:
macro add(x, y)
{
return x+y;
}
Příklad použití makra:
module macros;
import std::io;
macro add(a, b)
{
return a+b;
}
fn void main()
{
int x = 1;
int y = 2;
io::printf("%d + %d = %d\n", x, y, add(x, y));
}
Po překladu a spuštění tohoto demonstračního příkladu se (podle očekávání) vypočte hodnota 3:
1 + 2 = 3
4. Expanze makra pro hodnoty různých datových typů
Makro add, které jsme definovali, nemá specifikováno, jakého typu mohou být jeho parametry. Z tohoto pohledu se makro chová jako funkce s generickými typy, která je volána v čase překladu. To ovšem znamená, že můžeme makro add zavolat s předáním hodnot libovolného typu, pro který je definován operátor součtu (+). To si ostatně můžeme velmi snadno ověřit ve druhém demonstračním příkladu, v němž pomocí makra sečteme dvě celočíselné hodnoty, následně dvě hodnoty s plovoucí řádovou čárkou a dokonce i prvky dvou vektorů:
module macros;
import std::io;
macro add(x, y)
{
return x+y;
}
fn void main()
{
int x = 1;
int y = 2;
io::printf("%d + %d = %d\n", x, y, add(x, y));
float u = 1.1;
float v = 2.2;
io::printf("%f + %f = %f\n", u, v, add(u, v));
int[<10>] a = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
int[<10>] b = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
io::printf("%s + %s = %s\n", a, b, add(a, b));
}
Výsledky ukazují, že expanze tohoto makra proběhla bez problému:
1 + 2 = 3 1.100000 + 2.200000 = 3.300000 [<1, 2, 3, 4, 5, 6, 7, 8, 9, 10>] + [<1, 2, 3, 4, 5, 6, 7, 8, 9, 10>] = [<2, 4, 6, 8, 10, 12, 14, 16, 18, 20>]
5. Problematika závorek v klasických céčkovských makrech vs. makra v C3
V těle makra add nebyly použity žádné závorky, což může být z pohledu programátora, který je zvyklý na systém maker v jazyku C, poněkud matoucí. Mohlo by se dokonce zdát, že naše makro není napsáno korektně. Zkusme tedy namísto makra add nadefinovat makro mul určené pro součin dvou předaných výrazů:
macro mul(a, b)
{
return a*b;
}
Toto makro zavoláme a předáme mu výrazy x+y:
int z = mul(x+y, x+y);
Otázkou je, která z následujících expanzí se provede:
x+y*x+y // prostá textová expanze (x+y)*(x+y) // "inteligentní" expanze
To si snadno otestujeme předáním hodnot 1 a 2; pokaždé by se totiž měla vypočítat jiná hodnota:
1+2*1+2 = 5 (1+2)*(1+2) = 9
Otestujme si to:
module macros;
import std::io;
macro mul(a, b)
{
return a*b;
}
fn void main()
{
int x = 1;
int y = 2;
int z = mul(x+y, x+y);
io::printf("%d\n", z);
}
Výsledkem bude zpráva:
9
V jazyku C3 tedy není nutné jednotlivé parametry makra závorkovat.
6. Uzávorkování parametrů makra v céčku
V programovacím jazyku C jsme většinou nuceni uzavřít v těle makra jména parametrů do závorek, protože C provádí pouze textovou substituci. Pokud na závorky zapomeneme, nemusí být provedené výpočty korektní. Otestujme si to na céčkové obdobě makra mul, ve kterém neprovedeme uzávorkování:
#include <stdio.h>
#define mul(a, b) a*b
void main(void)
{
int x = 1;
int y = 2;
int z = mul(x+y, x+y);
printf("%d\n", z);
}
Zdrojový kód bude po expanzi makra vypadat takto:
void main(void)
{
int x = 1;
int y = 2;
int z = x+y*x+y;
printf("%d\n", z);
}
Výsledkem bude nesprávná hodnota:
5
Oprava spočívá v ručním uzávorkování všech parametrů makra v jeho těle:
#include <stdio.h>
#define mul(a, b) (a)*(b)
void main(void)
{
int x = 1;
int y = 2;
int z = mul(x+y, x+y);
printf("%d\n", z);
}
Výsledek po expanzi makra:
void main(void)
{
int x = 1;
int y = 2;
int z = (x+y)*(x+y);
printf("%d\n", z);
}
Nyní bude vypočtený výsledek korektní:
9
7. Makro expandované ve složitějším výrazu: varianta pro jazyk C3
V programovacím jazyku C se u maker, které mohou být expandovány v rámci složitějšího výrazu, navíc uzavírá i celé tělo makra do závorek, aby bylo expandované makro do výsledného výrazu vloženo korektním způsobem. V jazyku C3 to však dělat nemusíme, o čemž se můžeme snadno přesvědčit překladem a spuštěním následujícího příkladu:
module macros;
import std::io;
macro add_mul(a, b)
{
return a*b+1;
}
fn void main()
{
int x = 1;
int y = 2;
int z = add_mul(x+y, x+y);
int w = add_mul(x+y, x+y)*2;
io::printf("%d\n", z);
io::printf("%d\n", w);
}
Vypsané výsledky:
10 20
To znamená, že se provedou následující dva výpočty:
((1+2) * (1+2) + 1) ((1+2) * (1+2) + 1) * 2
a nikoli pouze:
(1+2) * (1+2) + 1 (1+2) * (1+2) + 1 * 2
8. Makro expandované ve složitějším výrazu: varianta pro jazyk C
V programovacím jazyku C, i když máme v makru správně uzávorkovány jednotlivé parametry, nebude expanze makra do složitějšího výrazu korektní, pokud celé tělo makra nebude uzávorkováno. V případě, že příklad z předchozí kapitoly přepíšeme do céčka, snadno zjistíme, proč tomu tak je:
#include <stdio.h>
#define add_mul(a, b) (a)*(b)+1
void main(void)
{
int x = 1;
int y = 2;
int z = add_mul(x+y, x+y);
int w = add_mul(x+y, x+y)*2;
printf("%d\n", z);
printf("%d\n", w);
}
Z výsledku expanze makra vyplývá, že skutečně chybí uzávorkování expandovaného těla makra:
void main(void)
{
int x = 1;
int y = 2;
int z = (x+y)*(x+y)+1;
int w = (x+y)*(x+y)+1*2;
printf("%d\n", z);
printf("%d\n", w);
}
V céčku je tedy nutné namísto:
a*b+1
tělo makra napsat (skoro LISPovským způsobem):
((a)*(b)+1)
Ověřme si to na upraveném příkladu:
#include <stdio.h>
#define add_mul(a, b) ((a)*(b)+1)
void main(void)
{
int x = 1;
int y = 2;
int z = add_mul(x+y, x+y);
int w = add_mul(x+y, x+y)*2;
printf("%d\n", z);
printf("%d\n", w);
}
Nyní bude výsledek expanze makra korektní:
void main(void)
{
int x = 1;
int y = 2;
int z = ((x+y)*(x+y)+1);
int w = ((x+y)*(x+y)+1)*2;
printf("%d\n", z);
printf("%d\n", w);
}
9. Specifikace datových typů v definici makra
V jazyku C3 je umožněno, aby se v definici makra (resp. v jeho hlavičce) mohly specifikovat typy parametrů makra. Tento přístup není v původním jazyku C vůbec možný, protože se překlad provádí až po textové expanzi maker.
Naše makro add přepíšeme do takové podoby, že bude akceptovat pouze parametry (konstanty či výrazy) typu int:
module macros;
import std::io;
macro add(int x, int y)
{
return x+y;
}
fn void main()
{
int x = 1;
int y = 2;
io::printf("%d + %d = %d\n", x, y, add(x, y));
}
Tento demonstrační příklad bude možné bez problémů přeložit i spustit:
1 + 2 = 3
10. Pokus o expanzi makra s předáním parametrů nekorektních typů
Nyní si ověřme, jak se bude překladač programovacího jazyka C3 chovat v případě, pokud budeme chtít makro expandovat s předáním parametrů jiných typů, než jsou celá čísla:
module macros;
import std::io;
macro add(int x, int y)
{
return x+y;
}
fn void main()
{
int x = 1;
int y = 2;
io::printf("%d + %d = %d\n", x, y, add(x, y));
float u = 1.1;
float v = 2.2;
io::printf("%f + %f = %f\n", u, v, add(u, v));
int[<10>] a = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
int[<10>] b = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
io::printf("%s + %s = %s\n", a, b, add(a, b));
}
Podle očekávání nebude v tomto případě možné expanzi makra provést, takže překlad skončí chybou (resp. hned dvěma chybami):
17: float u = 1.1;
18: float v = 2.2;
19:
20: io::printf("%f + %f = %f\n", u, v, add(u, v));
^
(/home/ptisnovs/src/c3-examples/c3-macros/06_typed_macro.c3:20:44) Error: 'float' cannot implicitly be converted to 'int', but you may use a cast.
22: int[<10>] a = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
23: int[<10>] b = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
24:
25: io::printf("%s + %s = %s\n", a, b, add(a, b));
^
(/home/ptisnovs/src/c3-examples/c3-macros/06_typed_macro.c3:25:44) Error: You cannot cast 'int[<10>]' to 'int'.
11. Makra expandovaná do konstantních výrazů
Pokusme se makro add (nyní v jeho jednodušší podobě bez specifikace datových typů) použít při deklaraci konstanty. Makru taktéž předáváme konstanty, takže by to teoreticky mělo být možné:
module macros;
import std::io;
macro add(a, b)
{
return a+b;
}
fn void main()
{
const int X = 1;
const int Y = 2;
const int Z = add(X, Y);
io::printf("%d + %d = %d\n", X, Y, Z);
}
Překladač jazyka C3 ovšem takovou expanzi makra nedovolí, resp. po expanzi zjistí, že výsledkem není (z jeho pohledu) konstanta:
12: const int X = 1;
13: const int Y = 2;
14:
15: const int Z = add(X, Y);
^^^^^^^^^
(/home/ptisnovs/src/c3-examples/c3-macros/07_compile_time_1.c3:15:19) Error: The expression must be a constant value.
Tatáž chyba bude ohlášena i tehdy, pokud do makra předáme přímo celočíselné konstanty:
12: const int X = 1;
13: const int Y = 2;
14:
15: const int Z = add(1, 2);
^^^^^^^^^
(/home/ptisnovs/src/c3-examples/c3-macros/07_compile_time_1.c3:15:19) Error: The expression must be a constant value.
12. Parametry makra vyhodnocované v době překladu
Aby bylo možné makro add použít i pro inicializaci pojmenované konstanty hodnotou, musí být tato hodnota vypočtena v čase překladu. Makro musíme v tomto případě upravit do takové podoby, že jeho argumenty budou mít před svým jménem zapsán prefix dolaru. Tím překladači jazyka C3 oznámíme, že argumenty budou vyhodnoceny v čase překladu a výsledkem našeho makra add tedy bude konstantní výraz 1+2, který je vypočten (v čase překladu) a do pojmenované konstanty Z je dosazena konstanta 3:
module macros;
import std::io;
macro add($a, $b)
{
return $a+$b;
}
fn void main()
{
const int X = 1;
const int Y = 2;
const int Z = add(X, Y);
io::printf("%d + %d = %d\n", X, Y, Z);
}
13. Předání jména proměnné nebo složitějšího výrazu do argumentu začínajícího znakem $
Mohlo by se tedy zdát, že pokud před všechny argumenty makra přidáme znak dolaru, získáme „univerzální“ makro, které bude akceptovat jakékoli parametry a bude ho možné použít jak při volání funkce, tak i při definici konstanty. Ovšem ve skutečnosti tomu tak není, o čemž se můžeme snadno přesvědčit pokusem o překlad následujícího demonstračního příkladu:
module macros;
import std::io;
macro add($a, $b)
{
return $a+$b;
}
fn void main()
{
int x = 1;
int y = 2;
int z = add(x, y);
io::printf("%d + %d = %d\n", x, y, z);
}
V tomto případě překladač jazyka C3 ohlásí chybu, která je vlastně opakem předchozí chyby. Nyní totiž makro voláme s předáním jmen proměnných, což z pohledu překladače jazyka C3 obecně nejsou konstanty (i když zrovna v tomto případě by si to překladač odvodit mohl):
12: int x = 1;
13: int y = 2;
14:
15: int z = add(x, y);
^
(/home/ptisnovs/src/c3-examples/c3-macros/09_compile_time_3.c3:15:17) Error: A compile time parameter must always be a constant, did you mistake it for a normal parameter?
2:
3: import std::io;
4:
5: macro add($a, $b)
^^^
(/home/ptisnovs/src/c3-examples/c3-macros/09_compile_time_3.c3:5:7) Note: The definition was here.
14. Pokus o definici makra, které prohodí obsah dvou proměnných
Pokusme se o vytvoření makra pojmenovaného swap, které v té části zdrojového kódu, kde bude zapsáno jeho volání (expanze), prohodí obsah dvou proměnných. Pokud by makra byla v jazyku C3 realizována formou textových substitucí (tedy tak, jako je tomu v jazyku C), bylo by řešení relativně jednoduché a mohlo by vypadat následovně:
module macros;
import std::io;
macro void swap(a, b)
{
var temp = a;
a = b;
b = temp;
}
fn void main()
{
int x = 1;
int y = 2;
swap(x, y);
io::printf("%d, %d\n", x, y);
}
Tento demonstrační příklad je sice přeložitelný a spustitelný (neobsahuje tedy z pohledu překladače programovacího jazyka C3 syntaktické chyby), ovšem po jeho spuštění se vypíše:
1, 2
15. Druhá varianta makra pro prohození obsahu dvou proměnných
Aby bylo možné napsat korektní verzi makra swap pro prohození obsahu dvou proměnných, je nutné před parametry makra vložit znak # (hash). Tímto znakem se označuje symbol, který sice ještě není vyhodnocen, ale je vázán na místo, kde byl definován. V takovém případě bude makro expandováno podobně, jako je tomu v jazyku C.
V našem případě, pokud makro napíšeme následovně (pozor – ještě to není zcela korektní zápis):
macro void swap(#a, #b)
{
var temp = #a;
#a = #b;
#b = temp;
}
A makro zavoláme stylem:
int x = 1; int y = 2; swap(x, y);
Provede překladač jazyka C3 expanzi makra do přibližně této podoby:
int x = 1;
int y = 2;
{
int __temp = x;
x = y;
y = __temp;
}
16. Potenciálně nebezpečná makra
Ve skutečnosti nebude makro swap v takové podobě, v jaké jsme si ho ukázali v předchozí kapitole, přeložitelné. Operace, které bude toto makro provádět, jsou totiž potenciálně „nebezpečné“ (ovšem tím mocnější) a z tohoto důvodu překladač programovacího jazyka C3 vyžaduje, aby byl před jméno takového makra vložen znak zavináče:
macro void @swap(#a, #b)
{
var temp = #a;
#a = #b;
#b = temp;
}
Zavináč se v tomto případě používá i při volání makra, aby bylo i v tomto místě zdrojového kódu zcela zřejmé, že se nejedná o volání běžné funkce, ale o potenciálně komplikovanější operaci:
int x = 1; int y = 2; @swap(x, y);
Vše si pochopitelně můžeme otestovat:
module macros;
import std::io;
macro void @swap(#a, #b)
{
var temp = #a;
#a = #b;
#b = temp;
}
fn void main()
{
int x = 1;
int y = 2;
@swap(x, y);
io::printf("%d, %d\n", x, y);
}
Nyní by se již měl program přeložit a po jeho spuštění by se měly zobrazit hodnoty 2 a 1 (nikoli opačně):
2, 1
17. Makro s proměnným počtem argumentů
Překladač programovacího jazyka C3 umožňuje tvorbu (a pochopitelně i volání) maker s proměnným počtem argumentů. V hlavičce makra se tento proměnný počet argumentů označuje třemi tečkami:
macro int len(...)
{
...
...
...
}
V takovém makru jsou definovány symboly $vacount obsahující aktuální počet předaných argumentů, dále symbol $vaarg vracející vybraný argument tak, jakoby byl předán formou pozičního argumentu, $vaconst, který provádí podobnou činnost, ale pro konstantní argumenty, $vatype pro získání informace o typu n-tého argumentu a konečně symbol $vasplat využívaný například tehdy, pokud voláme jiný kód akceptující proměnný počet argumentů.
Podívejme se na velmi jednoduchý příklad, ve kterém je definováno makro vracející pouze počet předaných argumentů. Makro akceptuje libovolný počet argumentů a interně využívá symbol $vacount zmíněný v předchozím odstavci:
module macros;
import std::io;
macro int len(...)
{
return $vacount;
}
fn void main()
{
io::printf("%d\n", len(1, 2, 3, "foo", "bar", "baz"));
}
Po překladu a spuštění tohoto příkladu by se měla zobrazit hodnota:
6
18. Obsah navazujícího článku
V dnešním článku jsme si ukázali základy používání maker v jazyce C3, ovšem ve skutečnosti je makrosystém tohoto jazyka mnohem rozsáhlejší. Proto budeme v popisu makrosystému C3 pokračovat i v navazujícím článku, ve kterém si ukážeme komplikovanější makra, která již dokážou zasahovat do syntaxe zápisu zdrojových kódů (na druhou stranu se ovšem v žádném případě nedosahuje takových vyjadřovacích schopností, jaké má například makrosystém LISPovských jazyků).
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:
Následují odkazy na demonstrační příklady z článku předchozí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 | |
| 123 | 24_contract.c3 | kontrakt zapsaný před hlavičkou funkce | https://github.com/tisnik/c3-examples/blob/master/c3-functions/24_contract.c4 |
Demonstrační příklady z předchozího článku o funkcích v C3:
| # | Příklad | Stručný popis | Adresa |
|---|---|---|---|
| 145 | 01_add_macro.c3 | jednoduché makro, které může být expandováno v rámci výrazu | https://github.com/tisnik/c3-examples/blob/master/c3-macros/01_add_macro.c3 |
| 146 | 02_add_macro.c3 | makro je generické, lze použít s hodnotami různých typů | https://github.com/tisnik/c3-examples/blob/master/c3-macros/02_add_macro.c3 |
| 147 | 03_macro_expansion1.c | expanze makro provedená preprocesorem jazyka C (parametry nejsou uzávorkovány) | https://github.com/tisnik/c3-examples/blob/master/c3-macros/03_macro_expansion1.c |
| 148 | 03_macro_expansion2.c | expanze makro provedená preprocesorem jazyka C (parametry jsou uzávorkovány) | https://github.com/tisnik/c3-examples/blob/master/c3-macros/03_macro_expansion2.c |
| 149 | 03_macro_expansion.c3 | řešení v jazyku C3 bez nutnosti uzávorkování parametrů makra | https://github.com/tisnik/c3-examples/blob/master/c3-macros/03_macro_expansion.c3 |
| 150 | 04_macro_expansion1.c | expanze makro provedená preprocesorem jazyka C (tělo makra není v závorkách) | https://github.com/tisnik/c3-examples/blob/master/c3-macros/04_macro_expansion1.c |
| 151 | 04_macro_expansion2.c | expanze makro provedená preprocesorem jazyka C (tělo makra je v závorkách) | https://github.com/tisnik/c3-examples/blob/master/c3-macros/04_macro_expansion2.c |
| 152 | 04_macro_expansion.c3 | řešení v jazyku C3 bez nutnosti zápisu těla makra do závorek | https://github.com/tisnik/c3-examples/blob/master/c3-macros/04_macro_expansion.c3 |
| 153 | 05_typed_macro.c3 | makro s definicí typů parametrů | https://github.com/tisnik/c3-examples/blob/master/c3-macros/05_typed_macro.c3 |
| 154 | 06_typed_macro.c3 | makro s definicí typů parametrů: příklad jeho expanze | https://github.com/tisnik/c3-examples/blob/master/c3-macros/06_typed_macro.c3 |
| 155 | 07_compile_time1.c3 | expanze makra v čase překladu: nefunkční varianta s konstantami | https://github.com/tisnik/c3-examples/blob/master/c3-macros/07_compile_time1.c3 |
| 156 | 08_compile_time2.c3 | expanze makra v čase překladu: funkční varianta s konstantami | https://github.com/tisnik/c3-examples/blob/master/c3-macros/08_compile_time2.c3 |
| 157 | 09_compile_time3.c3 | expanze makra v čase překladu: nefunkční varianta s proměnnými | https://github.com/tisnik/c3-examples/blob/master/c3-macros/09_compile_time3.c3 |
| 158 | 10_swap_macro1.c3 | realizace makra pro prohození obsahu dvou proměnných: nefunkční varianta | https://github.com/tisnik/c3-examples/blob/master/c3-macros/10_swap_macro1.c3 |
| 159 | 11_swap_macro2.c3 | realizace makra pro prohození obsahu dvou proměnných: funkční varianta | https://github.com/tisnik/c3-examples/blob/master/c3-macros/11_swap_macro2.c3 |
| 160 | 12_varargs.c3 | makro s proměnným počtem argumentů | https://github.com/tisnik/c3-examples/blob/master/c3-macros/12_varargs.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 - Anonymous function
https://en.wikipedia.org/wiki/Anonymous_function - Closure (computer programming)
https://en.wikipedia.org/wiki/Closure_(computer_programming) - How to implement closures in C
https://hokstad.com/how-to-implement-closures - An Overview of Macros in Rust
http://words.steveklabnik.com/an-overview-of-macros-in-rust - A Practical Intro to Macros in Rust 1.0
https://danielkeep.github.io/practical-intro-to-macros.html - The Rust Programming Language: macros
https://doc.rust-lang.org/beta/book/macros.html - Rust by example: 15 macro_rules!
http://rustbyexample.com/macros.html