:-) Musím říct, že už je v C viděl takové hrůzy, že jsem se chvíli seriózně zamyslel, proč by to nemělo být "2 2".
Obzvlášť lcamtuf má výborné chuťovky:
- https://infosec.exchange/@lcamtuf/116698470421521425
- https://infosec.exchange/@lcamtuf/116688667249299718
- https://infosec.exchange/@lcamtuf/116680893840332951
- https://infosec.exchange/@lcamtuf/116677328136469512
(atd...)
Tak to je peklo.
Prvni 3, to my trvalo nez jsem rozklicoval co to ma delat.
Posledni jsem vzdal. Podle vseho je to nejaka platformove zavisla feature.
PS: Uz se to zacina podobat tomuto.
https://vtm.zive.cz/clanky/14-nejsilenejsich-programovacich-jazyku-ze-kterych-vam-praskne-hlava/sc-870-a-239220
jj to je skutečně hodně peklíčko. Až se zpětně divím, že tu kdysi nevyhlášenou soutěž C vs Pascal nakonec vyhrálo céčko (asi proto, že mělo lepší startovní pozici?).
S klíčovým slovem register je to podobné jako s inline. Kromě specifického využití v případě static inline nemá smysl mikrooptimalizovat pomocí inline, protože a) překladače to umí většinou lépe, b) výkonnostní problém zcela určitě není v tom, že něco je nebo není inline.
Jinak typeof bylo užitečné i před přidáním auto v případě maker (a rozšíření ({ .... })), například:
#define SWAP(a, b) \
{ \
typeof(a) __tmp_swap = a;
a = b; \
b = __tmp_swap; \
}
#define MOVE_OWNERSHIP(source) \
({ \
__typeof__(source) __ownership = (source); \
(source) = NULL; \
__ownership; \
})
Userspace RCU používá typeof také poměrně hojně.
4. 8. 2026, 07:20 editováno autorem komentáře
Jen jsem tam teda zahlédl pár tradičních makro pastí, do kterých nějaký začátečník spolehlive spadne :)
S tím inline jo a ne. Když tu funkci chci strčit do headeru aby to překladač mohl inlinovat, tak tam to inline dát musím.
Pak je taky třeba Ob1 ve visual studiu, kde to bez inline inlinovat nebude.
Ale já jsem primárně na C++, my to inline máme trochu příčetnější.
Ono C není jazyk, ale rodina vzájemně nekompatibilních jazyků, které se jen zákeřně podobají :)
A v dřevních dobách C11+:
#include <stddef.h>
#include <string.h>
#define SWAP(a, b) \
do { \
/* Check size */ \
_Static_assert(sizeof((a)) == sizeof((b)), "SWAP() arguments have different size, check usage" ); \
/* Ensure alignment of __tmp_swap */ \
union { \
char buf[sizeof((a))]; \
max_align_t max_align; \
} __tmp_swap; \
/* Moves */ \
memcpy(__tmp_swap.buf, &(a), sizeof((a))); \
(a) = (b); \
memcpy(&(b), __tmp_swap.buf, sizeof((b))); \
} while (0)
Tohle makro má malou drobnou výhodu, kterou většinou nepotřebujete, a to, že funguje i na non-aligned proměnných. Ale FTR je lepší použít `memmove()` (a to i přes to, že většina implementací už má `memcpy()`, které funguje i pro překrývající se paměťové oblasti).
4. 8. 2026, 14:49 editováno autorem komentáře
K čemu memmove? Ten temp by se už z principu neměl překrývat s ničím.
Tady už je možná lepší použít memcpy, protože UB aspoň v nějakém validačním režimu dává překladači možnost hlásit chybu.
BTW ten max_align_t z předchozího příkladu je všechno jen ne "max". Třeba na SSE/AVX typy rozhodně nestačí (teda na memcpy jo, ale memcpy musí zvládnout zarovnání na char). To samé [u]intmax_t. Kvůli zpětné kompatibilitě ho jaksi nejde zvětšit. :)
4. 8. 2026, 14:59 editováno autorem komentáře
memcpy je neco jako povestne goto - nepouzivat
proto se doporucuje mit zazito pouzivat memmove a na memcpy zapomenout
> memcpy je neco jako povestne goto - nepouzivat
Proč? memove netuší, jestli ten překryv je správně nebo je to bug. Použitím memcpy říkám, že se ta paměť nesmí překrývat, takže mi to může ubsan nebo něco podobného chytnout. memmove to nechytne.
Ja som sa k tomu uchylil na ESP32 z dovodu, ze bud slo o nejaky malo pouzivany snippet pripadne kriticky blok, kde som nechcel aby zbytocne skakalo. Nebil by som sa o to, ze to bolo velmi dolezite a na desktope by som to asi tiez neriesil, ale v pripade C sa moze jednat o slabsie stroje, kde by to mohlo mat specificke vyuzitie.
V C29 to vyzera na revoluciu, bude podpovat defer (konecne prec s goto error;)
https://en.wikipedia.org/wiki/C29_(C_standard_revision)
Myslim, ze GCC15 ho uz z nejakym prepinacom podporuje.
Hlavně GCC i clang už hodně dlouhou řádku let podporují cleanup attribute, což je tedy syntakticky mnohem méně příjemné, ale dělá to to samé.
Vláďo, výhodu defer vidím v tom, že máš přístup ke všem lokální proměnným, takže do defer bloku můžeš nacpat i věci jako vyskočení z RCU kritické sekce nebo odemknutí mutexu. Obojí se samozřejmě dá udělat i přes __attribute__((__cleanup__)), ale není to nic hezkého...
Další věc je taky rozdíl mezi standardním chováním a gcc/clang rozšířením.
Linux je v tom dost specifický, protože se tu na jiné překladače moc nehraje a zároveň Linus poslal C do háje s některýma standardníma featurama.
Mně přijde, že na *BSD a macOS taky stačí podporovat clang+gcc. (a nejspíš i řadě jiných míst)
Pro mě osobně nejde ani tak o to, co je standard, ale že nově přidané chování (posledních pár let) není úplně dobře portabilní všude – různá "stabilní" distra a i jiná místa nemívají snadno nové verze kompilátorů.
11. 8. 2026, 10:15 editováno autorem komentáře
Asi tak, kvůli businessu RH/IBM trpí celý ekosystém.
gcc 8 s námi bude do roku 2029, gcc 11 do roku 2032.
Klucove slovo register je honorovane uplne bezne. Zo skusenosti to ma vplyv na alokator premennych a je tak stale mozne posunut premennu k alokacii do registra namiesto na zasobnik.
Mam presne jedno pouzitie toho registra v kode na mieste, kde saham do nastavenia zasobnika a potrebujem, aby sa tych par riadkov kodu nepouzival. Mam v tom kontexte ale aktivnu jednu lokalnu premennu. Je tagnuta klucovym slovom register a prekladac ju ochotne alokuje do registra aj v -O0 aj v -O2 buildoch.
Ondra ^ zase tvrdí, že ne, tak těžko si vybrat. Možná při tom -O0, ale to asi nikoho moc netrápí, či?
Ono když není specifikovaná platforma, překladač, jeho verze, flagy a spousta dalších věcí včetně postavení měsíce tak je těžké cokoliv tvrdit.
Nikdo nepíše ve standardním C, vždycky je to jeden z mnoha navzájem nekompatibilních dialektů.
on psal "Klucove slovo register je honorovane uplne bezne". Mozna je to jen o chapani slov "uplne bezne". gcc i clang to pri jakekoli optimalizaci ignoruji rekl bych.
Ono jde o to, v jakém kontextu. Co je "úplně běžné" v kontextu embedded vývoje je pro nás PCčkáře úplně jiný vesmír.
gcc mělo historicky pro "register" váhu jen "+1".
Interně vypočítaná váha, jestli má/nemá být proměnná v registru, byla násobně vyšší - odvozena od odhadnutém počtu přístupů, násobena počtem iterací cyklu.
"register" nebylo úplně ignorováno, ale v praxi to mělo minimální vliv.
Kdyby se náhodou potkaly dvě proměnné se stejnou váhou, pak hint "register" rozhodne, jinak ne.
Tady je godbolt.org - prosím ukažte nám případ, kdy překladač register neignoruje a je to reálný usecase.
> Klucove slovo register je honorovane uplne bezne.
Tak pak se asi s pisatelem neshodeme na tom, co to znamená "úplně běžně".
Ano, specializované překladače můžou klíčové slovo register pořád neignorovat, zvlášt pokud se vrtáte hodně blízko hardware, kde tyhle mikrooptimalizace stále dávají smysl.
Pisete 1st stage bootloader pro nejaky pidihardware nebo řešíte nejakou budu v hw?
Ci napojujete ovci na říční skebli?
Jinak my tyhle gymnastiky nedavaji smysl.
diky za clanek i diskuzi. u obojiho jsem se poucil i pobavil. idealni kombinace.
V moderním gcc 16.1 docela překvápko:
void main_w_register(void) {
register unsigned char a;
register unsigned char b;
register unsigned char c;
a = 10;
b = 20;
c = a + b;
}
"main_w_register":
push rbp
mov rbp, rsp
nop
pop rbp
ret