Je jazyk C skutočne ťažký?

Re:Je jazyk C skutočne ťažký?
« Odpověď #210 kdy: 13. 06. 2025, 09:39:41 »
Nedefinované chování umožňuje primitivní operace pokrýt jednou CPU intrukcí. Když bude definované všechno, na každou prkotinu bude knihovní funkce, která bude emulovat operátor přesně každý bit výsledku.

Teď jde použít oboje - rychlý operátor s nejistým chováním, nebo si zavolat funkci a mít výsledek pomalu, ale precizně.


Re:Je jazyk C skutočne ťažký?
« Odpověď #211 kdy: 13. 06. 2025, 11:21:18 »
Nedefinované chování umožňuje primitivní operace pokrýt jednou CPU intrukcí. Když bude definované všechno, na každou prkotinu bude knihovní funkce, která bude emulovat operátor přesně každý bit výsledku.

Teď jde použít oboje - rychlý operátor s nejistým chováním, nebo si zavolat funkci a mít výsledek pomalu, ale precizně.
Na tohle by bohatě stačilo implementačně definované chování (jako je třeba u signed dělení). Rozdíl oproti UB je velký :
- To chování se vždycky stane. Překladač nemůže předpokládat, že daná situace ve validním kódu nesmí nastat. Takže opravdu vygeneruje odpovídající CPU instrukce.
- Překladač/platforma musí zdokumentovat, jak se ta operace bude chovat.

Ve výsledku mám jednu CPU instrukci a žádné démony z nosa. :)


Re:Je jazyk C skutočne ťažký?
« Odpověď #213 kdy: 13. 06. 2025, 13:44:59 »
https://wordsandbuttons.online/so_you_think_you_know_c.html

5/5

Nikdy o sobě neřeknu, že dokonale ovládám češtinu, třebaže ji používám celý život. Ale myslím, že ji ovládám velmi obstojně, rozhodně dostatečně, abych v ní mohl vyjádřit jakoukoli svou myšlenku. Takhle přistupuji i k programovacím jazykům. Ve sveřepých šakalech chybu neudělám, ale jistě by se našel jiný špek, na který bych se nachytal. Jenže to, podle mě, není podstatné. O jazyku samotném to nic nevypovídá. Ukažte mi programovací jazyk, v němž nenajdete konstrukci, která by se dala považovat za špek. Někdo považuje vyjmenovaná slova za špek, někdo shodu podmětu s přísudkem. Ve skutečnosti to není nic komplikovaného na používání - s trochou cviku. Opravdovým špekům se lze i při pokročilém používání vyhnout.

Např. mnohými tolik opěvovaný Rust. Na mě působí dojmem, že přechodníky nemá, protože v nich spousta lidí dělá chyby, tak mě nutí místo nich použít nějaký krkolomný konstrukt.

Ink

  • *****
  • 686
    • Zobrazit profil
    • E-mail
Re:Je jazyk C skutočne ťažký?
« Odpověď #214 kdy: 14. 06. 2025, 13:04:09 »
Např. mnohými tolik opěvovaný Rust. Na mě působí dojmem, že přechodníky nemá, protože v nich spousta lidí dělá chyby, tak mě nutí místo nich použít nějaký krkolomný konstrukt.

Naopak. Rust má spoustu možností, jak cokoli naprasit jakkoli - počínaje inline asm, přes "normální" unsafe Rust až po FFI.  Kromě toho nabízí spoustu abstrakcí a pohodlných způsobů, jak se v normálním kódu vyvarovat různých problémů s pomocí jazyka. Na rozdíl třeba od C, které má jenom režim "pras jak umíš".
« Poslední změna: 14. 06. 2025, 13:08:07 od Ink »


Re:Je jazyk C skutočne ťažký?
« Odpověď #215 kdy: 15. 06. 2025, 12:37:30 »
Na rozdíl třeba od C, které má jenom režim "pras jak umíš".
Při práci v C taky fungujou příčetnějí režimy, které krotí ty nejprasáčtějí praktiky. Jen nejsou nijak vynucené jazykem, takže to hlídají lintery, code review a podobně.

Ink

  • *****
  • 686
    • Zobrazit profil
    • E-mail
Re:Je jazyk C skutočne ťažký?
« Odpověď #216 kdy: 15. 06. 2025, 13:17:03 »
Na rozdíl třeba od C, které má jenom režim "pras jak umíš".
Při práci v C taky fungujou příčetnějí režimy, které krotí ty nejprasáčtějí praktiky. Jen nejsou nijak vynucené jazykem, takže to hlídají lintery, code review a podobně.

Code review je ultimátní řešení, jenže má dvě nevýhody:

1. Není podpořené jazykem
2. Je opět závislé na lidském faktoru

Všechny ty bezpečnostní problémy v OpenSSL a jinde existovaly i přes možnost review člověkem a existenci linterů.

BoneFlute

  • *****
  • 2 033
    • Zobrazit profil
Re:Je jazyk C skutočne ťažký?
« Odpověď #217 kdy: 15. 06. 2025, 15:20:57 »
Na rozdíl třeba od C, které má jenom režim "pras jak umíš".
Při práci v C taky fungujou příčetnějí režimy, které krotí ty nejprasáčtějí praktiky. Jen nejsou nijak vynucené jazykem, takže to hlídají lintery, code review a podobně.

Jde o směr uvažování:
V C máte by default všechno nebezpečné, a snažíte se to nějak svázat.
V Rustu máte by default všechno bezpečné 1), a když potřebujete, můžete jít do rizika.

A v tomto uvažování se pak ty jazyky dělí. Mám pocit, že právě Zig jde spíše tou C cestou, zatímco třeba já nevím, třeba Haskell jdou spíše tou druhou.


1) Samozřejmě v rámci možností. Aby tu zase někdo nevytahoval, že v Rustu jde vytvořit špatný kód.

Zopper

  • *****
  • 904
    • Zobrazit profil
Re:Je jazyk C skutočne ťažký?
« Odpověď #218 kdy: 15. 06. 2025, 18:35:12 »
Na rozdíl třeba od C, které má jenom režim "pras jak umíš".
Při práci v C taky fungujou příčetnějí režimy, které krotí ty nejprasáčtějí praktiky. Jen nejsou nijak vynucené jazykem, takže to hlídají lintery, code review a podobně.
O to právě jde. Pokud můžu nějaký problém vyloučit, nebo zaručit výrazně menší dopad průšvihu tím, že to nechám na jazyku a překladači, tak proč přidávat práci reviewerovi? V C je skoro jakákoliv operace s pointerem nebo polem potenciální zdroj průšvihu, a člověk při review musí hlídat všechno. V jiných jazycích vím, že spoustu těchto rizik zabrání struktura jazyka/překladač, a když narazím na nějaký unsafe blok, tak vím, že si v něm musím dávat pořádný pozor - ten pozor, co v C potřebuji u každého řádku celého programu.

Re:Je jazyk C skutočne ťažký?
« Odpověď #219 kdy: 15. 06. 2025, 21:12:47 »
V jiných jazycích vím, že spoustu těchto rizik zabrání struktura jazyka/překladač, a když narazím na nějaký unsafe blok, tak vím, že si v něm musím dávat pořádný pozor - ten pozor, co v C potřebuji u každého řádku celého programu.

Nepříjemné je, že ten unsafe kód může záviset i na invariantech ze safe kódu (např. index do pole může spočítat safe kód), takže musíte dávat i pozor na safe kód. Respektive i změna v safe kódu pak může rozbít program.

Jinak samozřejmě, pokud ten unsafe kód napsal někdo, komu bezmezně věříte, že to udělal dobře a vystavil vám bezpečné safe rozhraní, tak jste v pohodě. Pokud ovšem ten unsafe kód píšete sám, tak se dostáváte do podobné situace jako v C s tím, že psaní unsafe kódu v nějakém bezpečném jazyce může být složitější než psaní C.

Např. moje osobní zkušenost je, že B-strom, jak je napsaný v unsafe kódu ve standardní knihovně Rustu v souboru node.rs, bych napsat nedokázal, ale v C-like jazyce ho napsat dokážu. Rozdíl je v tom, že v Rustu si člověk musí pohlídat mnohem víc invariantů než v C a kód je tam také kvůli tomu cca 2-3 delší než v C-like jazyce.

BoneFlute

  • *****
  • 2 033
    • Zobrazit profil
Re:Je jazyk C skutočne ťažký?
« Odpověď #220 kdy: 16. 06. 2025, 00:41:07 »
V jiných jazycích vím, že spoustu těchto rizik zabrání struktura jazyka/překladač, a když narazím na nějaký unsafe blok, tak vím, že si v něm musím dávat pořádný pozor - ten pozor, co v C potřebuji u každého řádku celého programu.

Nepříjemné je, že ten unsafe kód může záviset i na invariantech ze safe kódu (např. index do pole může spočítat safe kód), takže musíte dávat i pozor na safe kód. Respektive i změna v safe kódu pak může rozbít program.
Neptal jsem se posledně na nějakou ukázku? Bohužel si nevybavuji výsledek.

Rozdíl je v tom, že v Rustu si člověk musí pohlídat mnohem víc invariantů než v C
To mi nějak matematicky nevychází.
Logika vytvoří stejné množství stavů. Rust s unsafe ti část pohlídá, C ti nepohlídá žádné.

Re:Je jazyk C skutočne ťažký?
« Odpověď #221 kdy: 16. 06. 2025, 04:46:54 »
Nepříjemné je, že ten unsafe kód může záviset i na invariantech ze safe kódu (např. index do pole může spočítat safe kód), takže musíte dávat i pozor na safe kód. Respektive i změna v safe kódu pak může rozbít program.
Neptal jsem se posledně na nějakou ukázku? Bohužel si nevybavuji výsledek.

Příklad je na stránce Working with Unsafe, před odstavcem


This program is now unsound, Safe Rust can cause Undefined Behavior, and yet we only modified safe code. This is the fundamental problem of safety: it's non-local. The soundness of our unsafe operations necessarily depends on the state established by otherwise "safe" operations.


Rozdíl je v tom, že v Rustu si člověk musí pohlídat mnohem víc invariantů než v C
To mi nějak matematicky nevychází.
Logika vytvoří stejné množství stavů. Rust s unsafe ti část pohlídá, C ti nepohlídá žádné.

Mé tvrzení se týká jen toho B-stromu, konkrétně jen node.rs (nechci se pouštět do obecných tvrzení). Implementace Rustu má kvůli borrow checkeru spoustu zbytečných funkcí, které v C nepotřebuji - např. tyhle

Kód: [Vybrat]
impl<K, V, Type> NodeRef<marker::Owned, K, V, Type> {
    /// Mutably borrows the owned root node. Unlike `reborrow_mut`, this is safe
    /// because the return value cannot be used to destroy the root, and there
    /// cannot be other references to the tree.
    pub(super) fn borrow_mut(&mut self) -> NodeRef<marker::Mut<'_>, K, V, Type> {
        NodeRef { height: self.height, node: self.node, _marker: PhantomData }
    }

    /// Slightly mutably borrows the owned root node.
    pub(super) fn borrow_valmut(&mut self) -> NodeRef<marker::ValMut<'_>, K, V, Type> {
        NodeRef { height: self.height, node: self.node, _marker: PhantomData }
    }

    /// Irreversibly transitions to a reference that permits traversal and offers
    /// destructive methods and little else.
    pub(super) fn into_dying(self) -> NodeRef<marker::Dying, K, V, Type> {
        NodeRef { height: self.height, node: self.node, _marker: PhantomData }
    }
}

To jsou funkce, které se samotným B-stromem nijak nesouvisí, takže je v jiných jazycích nepotřebuji.

Ink

  • *****
  • 686
    • Zobrazit profil
    • E-mail
Re:Je jazyk C skutočne ťažký?
« Odpověď #222 kdy: 16. 06. 2025, 07:56:18 »
Mé tvrzení se týká jen toho B-stromu, konkrétně jen node.rs (nechci se pouštět do obecných tvrzení). Implementace Rustu má kvůli borrow checkeru spoustu zbytečných funkcí, které v C nepotřebuji - např. tyhle

Kód: [Vybrat]
impl<K, V, Type> NodeRef<marker::Owned, K, V, Type> {
    /// Mutably borrows the owned root node. Unlike `reborrow_mut`, this is safe
    /// because the return value cannot be used to destroy the root, and there
    /// cannot be other references to the tree.
    pub(super) fn borrow_mut(&mut self) -> NodeRef<marker::Mut<'_>, K, V, Type> {
        NodeRef { height: self.height, node: self.node, _marker: PhantomData }
    }

    /// Slightly mutably borrows the owned root node.
    pub(super) fn borrow_valmut(&mut self) -> NodeRef<marker::ValMut<'_>, K, V, Type> {
        NodeRef { height: self.height, node: self.node, _marker: PhantomData }
    }

    /// Irreversibly transitions to a reference that permits traversal and offers
    /// destructive methods and little else.
    pub(super) fn into_dying(self) -> NodeRef<marker::Dying, K, V, Type> {
        NodeRef { height: self.height, node: self.node, _marker: PhantomData }
    }
}

To jsou funkce, které se samotným B-stromem nijak nesouvisí, takže je v jiných jazycích nepotřebuji.

Troufám si tvrdit, že něco podobného běžný programátor v Rustu neimplementuje. Je jistě možné se točit na jedné okrajové situaci, ale pak se dostáváme k banálnímu přístupu obhájců C - můžeme si to všechno udělat jednoduše a tady to zrovna vypadá, že se to vyplatí.

BoneFlute

  • *****
  • 2 033
    • Zobrazit profil
Re:Je jazyk C skutočne ťažký?
« Odpověď #223 kdy: 16. 06. 2025, 22:22:55 »
Nepříjemné je, že ten unsafe kód může záviset i na invariantech ze safe kódu (např. index do pole může spočítat safe kód), takže musíte dávat i pozor na safe kód. Respektive i změna v safe kódu pak může rozbít program.
Neptal jsem se posledně na nějakou ukázku? Bohužel si nevybavuji výsledek.

Příklad je na stránce Working with Unsafe, před odstavcem


This program is now unsound, Safe Rust can cause Undefined Behavior, and yet we only modified safe code. This is the fundamental problem of safety: it's non-local. The soundness of our unsafe operations necessarily depends on the state established by otherwise "safe" operations.


Děkuji za příspěvek.

Viděl bych tam následující problém:

Kód: [Vybrat]
fn index(idx: usize, arr: &[u8]) -> Option<u8> {
    if idx <= arr.len() {
        unsafe {
            Some(*arr.get_unchecked(idx))
        }
    } else {
        None
    }
}

V tom unsafe kódu pracuji s proměnnou (idx), která má špatný rozsah. Není nijak směrodatné, že kontroluju rozsah v safe části. (Naopak, je to rozumné, protože to bude v tomto případě jednodužší.) Ta kontrola je chybná, a díky tomu je chybné i chování unsafe části. Vstoupil jsem do unsafe části, čímž jsem si vypnul (některé) kontroly, a celkem jasně tam mám proměnnou, kterou si táhnu z vnějšího safe kontextu, a mám na něj nějaké předpoklady, tak bych si ty předpoklady měl jako programátor ověřit. Neudělal jsem to, chyba.

V tom druhém případě je to podobný princip.

Úplně v tom nevidím tu katastrofu, kterou v tom pozoruješ ty. Hmm.



V každém případě ta matematika nevychází.

Mám-li v kódu jednu chybu, tak mám v kódu jednu chybu. Je dost dobře jedno, jestli se projeví tady nebo tam. A ano, může se množit. Ale stále mám v kódu jednu chybu. Skutečnost, že se chyba projeví v safe Rust neznamená, že ta chyba je v této části. Opravovat ji musím tam, kde je. Ano, může to být složitější. Tak on Rust prostě je složitější.

Pokud přijmu tvé tvrzení, že unsafe Rust vyžaduje cca třikrát tolik kódu jak C, tak jakmile napíšu kód, kde bude poměr větší jak 3:1 Safe versus Unsafe, už jsem na tom lépe jak čistý C kód  :D


Ano, psaní unsafe je třeba věnovat péči, ale nevidím v tom důvod přecházet na jazyk z kategorie unsafe by default. I kdyby ta péče měla být třikrát tak větší.