Zobrazit příspěvky

Tato sekce Vám umožňuje zobrazit všechny příspěvky tohoto uživatele. Prosím uvědomte si, že můžete vidět příspěvky pouze z oblastí Vám přístupných.


Příspěvky - vrit

Stran: [1] 2 3 4
1
Vývoj / Re:Je jazyk C skutočne ťažký?
« kdy: 11. 06. 2025, 15:06:01 »
Já když říkám že píšu v C, tak mluvím o syntaxi jazyka. Že ty v tom vidíš standard a nedokázal bys napsat driver který musí zapsat na adresu 0 protože bys měl panickou hrůzu že to je undefined behaviour, to je tvoje mínus. Já jsem pragmatik a flexi. Kde to jde tak píšu portabilní kód, kde to nejde tak platform specific. A jestli tomu říkáš že nepíšu v C, tak si tomu tak říkej, je mě to celkem šumák. Asi vlastně nemám dále co bych tady k diskuzi přispěl, jsem diskvalifikován se o C vůbec bavit, protože dělám embedded věci. Oukej.
Ale to se týká i embedded. I v embedded musíš řešit, že je dereference null pointeru undefined behavior. Dám ti praktický příklad. Jsou mikrokontroléry, které mají RAM v paměťové mapě od adresy 0, takže adresa 0 je naprosto validní pointer do RAM. Co s tím? Vyřeší se to tak, že se RAM zadefinuje od adresy 1 a adresa 0 se ignoruje, abychom se vyhnuli problémům s dereferencí null pointeru. Přijdeme o jeden bajt RAM na mikrokontroléru, ale to je nízká cena za vyřešení problémů s adresou 0 a undefined behavior.

Jenže na té adrese může být registr která má nenahraditelnou speciální funkci či význam. To je naprostý nesmysl to řešit tak jak říkáš. To může udělat jenom teoretik který k tomu prakticky nikdy nečmuch.

Normálně se otestuje překladač zda to podporuje a když ne, tak se vybere jiný. Takhle se to v praxi řeší.
Případně se použije inline assembler.

Těžko očekávat že nejaký kód handlující absolutní adresy registrů se bude někam přenášet. Proto je undefined behaviour úplně jedno.

2
Vývoj / Re:Je jazyk C skutočne ťažký?
« kdy: 11. 06. 2025, 14:37:33 »
Zápis přes pointer na adresu v paměti je naprosto standardní věc v C. To jenom ty zase musíš vytahovat nějaké speciality jako adresa 0 abys ukázal že jsi věčný troublemaker. Good job :D
Já jen cituji C standard, kde je explicitně uvedeno, že dereference null pointeru je undefined behavior. Rozumím tomu, že C standard nemáš přečtený a nevíš to. Nerozumím ale tomu, proč si pořád v opozici a snažíš se tvrdit, že zápis na jakoukoliv adresu přes pointer je v pohodě? Není to v pohodě, zápis na adresu 0 je dle C standardu undefined behavior. Ve chvíli, kdy to uděláš, tak od toho C standard dává ruce pryč a takový program může dělat cokoliv.

Já když říkám že píšu v C, tak mluvím o syntaxi jazyka. Že ty v tom vidíš standard a nedokázal bys napsat driver který musí zapsat na adresu 0 protože bys měl panickou hrůzu že to je undefined behaviour, to je tvoje mínus. Já jsem pragmatik a flexi. Kde to jde tak píšu portabilní kód, kde to nejde tak platform specific. A jestli tomu říkáš že nepíšu v C, tak si tomu tak říkej, je mě to celkem šumák. Asi vlastně nemám dále co bych tady k diskuzi přispěl, jsem diskvalifikován se o C vůbec bavit, protože dělám embedded věci. Oukej.

3
Vývoj / Re:Je jazyk C skutočne ťažký?
« kdy: 11. 06. 2025, 14:06:27 »
Píšu v C. Kde mám platform/compiler specific věci, tak použiju #ifdef a do poslední #else větve dám error "not implemented" a nechám toho kdo to někdy bude v budoucnu potřebovat, aby ty #else větve dopsal. Nebudu paralyzovat celý vývoj jenom kvůli tomu abych všem linuxákům vyhověl. Za to mě zákazník neplatí.
Nepíšeš v C. Ve chvíli, kdy uděláš dereferenci null pointeru nebo jiné undefined behavior, tak od toho C standard dává ruce pryč. Na některých platformách takové věci můžou dávat smysl, ale vždy musíš explicitně zdůraznit, že se jedná o platformově závislou věc, kterou musíš speciálně řešit, např. nějakými flagy překladače. Ty to tady prezentuješ jako něco normálního, ale děláš je pravý opak, pohybuješ se mimo C stadard a musíš to záplatovat nějakými ohýbáky.

Nesmysl. Zápis přes pointer na adresu v paměti je naprosto standardní věc v C. To jenom ty zase musíš vytahovat nějaké speciality jako adresa 0 abys ukázal že jsi věčný troublemaker. Good job :D

4
Vývoj / Re:Je jazyk C skutočne ťažký?
« kdy: 11. 06. 2025, 13:49:21 »
To mě ale nezajímá, mě zajíma jaký bude strojový kód a co program dělá a jestli dělá to co chci.
V pořádku, ale neříkej potom, že píšeš v C. Nepíšeš totiž v C, ale v nějakém vrid dialektu, kdy jsou tvoje programy funkční jen s konkrétním nastavením překladače na konkrétní platformě.

Píšu v C. Kde mám platform/compiler specific věci, tak použiju #ifdef a do poslední #else větve dám error "not implemented" a nechám toho kdo to někdy bude v budoucnu potřebovat, aby ty #else větve dopsal. Nebudu paralyzovat celý vývoj jenom kvůli tomu abych všem linuxákům vyhověl. Za to mě zákazník neplatí.

5
Vývoj / Re:Je jazyk C skutočne ťažký?
« kdy: 11. 06. 2025, 13:41:09 »
Prostě si překladač nastavím jak potřebuju.
Můžeš prohlásit, že dereference pointeru není undefined behavior. Můžeš i zkusit donutit překladač, aby při dereferenci null pointeru dělal něco definovaného. Nemáš pak ale validní C program. Máš program, který je dle C standardu nefunkční, standard říká, že nedefinuje jeho chování.

To mě ale nezajímá, mě zajíma jaký bude strojový kód a co program dělá a jestli dělá to co chci.

6
Vývoj / Re:Je jazyk C skutočne ťažký?
« kdy: 11. 06. 2025, 13:20:06 »
To nema s GCC nic společného. Takhle se psalo jestě než nějaký GCC vůbec existoval. A ani to nemá nutně nic společného s adresou 0. Prostě obecně když mám pointer a přectu přes něj nebo zapíšu, tak čtu nebo zapisuju z nějaké adresy v paměti která odpovídá hodnotě pointeru. Tady nic nestandardního není.
Pořád tomu nerozumíš. Nevadí, zkusím to vysvětlit znovu. null pointer (adresa 0) se v C standardu ošetřuje speciálně. C standard explicitně říká, že dereference null pointeru je undefined behavior. Tozn. pokud máš v C programu čtení nebo zápis adresy 0, překladač s tím může udělat cokoliv (a taky dělá). Může to ignorovat, může vygenerovat neplatnou instrukci, může to dokonce i fyzicky provést. Jakékoliv chování, včetně všech zmíněných, je při dereferenci null pointeru legální.

Já tomu rozumím a chápu to. Já jenom nechápu co s tím máš za problém. Prostě si překladač nastavím jak potřebuju. Když píšu driver nebo knihovnu pro MCU kde tam potřebuju opravdu zapsat, tak si to tak nastavím. Když píšu program běžící v rámci OS tak to samozřejmě nechám generovat ud2 instrukci abych to odchytil v debuggeru. To že přes pointer se dá zapisovat na adresu a že toto je platné v C všude stále platí. Hodnota 0 může být speciálně handlovaná překladačem, ale to je optional. Tak samo ale může být potřeba vytvořit program který to cíleně dělá a překladač by to měl umožnit (alespoň nějakým přepínačem jako to má GCC).

7
Vývoj / Re:Je jazyk C skutočne ťažký?
« kdy: 11. 06. 2025, 13:11:40 »
Kód: [Vybrat]
uint32_t *p_u32 = 0x00000040;
*p_u32 = 0x12345678; // zapiš hodnotu 0x12345678 na adresu 0x00000040

Toto je naprosto legitimní C-kód, sic platform specific.

To není tak úplně pravda. Tohle je legální jen s "volatile". Jinak bude optimalizátor provádět psí kusy.
Jasně, může. Ale o to mi zrovna nešlo. Šlo mi o to že v C je standard zapisovat přes pointer na paměťové adresy, nebo z nich číst. To že to může vyvolat něco co nechci, v závislosti na runtime environmentu je až druhotná věc.

Tady jsem ze srandy přeložil kód pro různé platformy, různými překladači a všechny zapíší na adresu 0x40 4 bajty s hodnotou 0x12 0x34 0x56 0x78. Takže jaképak jenom GCC, jakýpak nestandard?

Mimochodem, nepoužil jsem volatile, i když s ním je to jistota - to souhlas.

Kód: [Vybrat]
--- arm7 clang
f:
        ldr     r0, .LCPI0_0
        mov     r1, #64
        str     r0, [r1]
        bx      lr
.LCPI0_0:
        .long   305419896

--- gcc
f():
        mov     DWORD PTR ds:64, 305419896
        ret

--- djgpp
__Z1fv:
        mov     DWORD PTR ds:64, 305419896
        ret

--- icc
f:
..B1.1:                         # Preds ..B1.0
        mov       DWORD PTR [64], 305419896                     #6.6
        ret                                                     #7.1

--- avr-gcc
f:
.L__stack_usage = 0
        ldi r24,lo8(120)
        ldi r25,lo8(86)
        ldi r26,lo8(52)
        ldi r27,lo8(18)
        out 0x20,r24
        out 0x21,r25
        out 0x22,r26
        out 0x23,r27
        ret

8
Vývoj / Re:Je jazyk C skutočne ťažký?
« kdy: 11. 06. 2025, 12:40:02 »
A jak zapíšu do registru který je na adrese 0x00000000
Nezapíšeš. Protože gcc ti na tohle, v závislosti na optimalizacích, verzi překladače a fázi měsíce vygeneruje ud2 isntrukci. A proč? Protože může, je to undefined behavior, norma takové chování povoluje.

https://godbolt.org/z/bGqsEqsYc

Tak překladač má být správně nastaven podle toho co dělám...
Kód: [Vybrat]
-O2 -fno-delete-null-pointer-checks
https://godbolt.org/z/TTfc87sxb

Kód: [Vybrat]
test():
        mov     DWORD PTR ds:0, 1
        ret
-fno-delete-null-pointer-checks je nestandardní gcc rozšíření. Otázka zněla, jak ve standardním C zapsat na adresu 0. Odpověd je, že to ve standardním C NELZE, protože dereference null pointeru je dle C standardu undefined behavior.

To nema s GCC nic společného. Takhle se psalo jestě než nějaký GCC vůbec existoval. A ani to nemá nutně nic společného s adresou 0. Prostě obecně když mám pointer a přectu přes něj nebo zapíšu, tak čtu nebo zapisuju z nějaké adresy v paměti která odpovídá hodnotě pointeru. Tady nic nestandardního není.

To proč je to undefined behaviour je, protože záleží na runtime environment co takový zápis nebo čtení způsobí. Na té adrese může být registr jehož vyčtením se vyclearujou flagy, nebo to může být obyčejná paměťová buňka. Ale to je undefined behaviour v obecné rovině. To vůbec neznamená že to nemůžu pro architecture (environment) specific kód použít a už vůbec to neznamená že by se nemělo na adresu zapsat nebo z ní přečíst když použiju pointer.

Kód: [Vybrat]
uint32_t *p_u32 = 0x00000040;
*p_u32 = 0x12345678; // zapiš hodnotu 0x12345678 na adresu 0x00000040

Toto je naprosto legitimní C-kód, sic platform specific.

9
Vývoj / Re:Je jazyk C skutočne ťažký?
« kdy: 11. 06. 2025, 11:34:42 »
V assembleru jo. Ale v C (bez nějakých nadstandardních flagů) to nesmíš. Takže ten vygenerovaný kód občas vypadá dost překvapivě.

A proč bych to jako nesměl? C není nijak limitované na prostředí kde je nějaký operační systém. V C lze psát jak high-level aplikace tak i low-level drivery které zapisují/nebo čtou na/z fixních adres. Takže nějakému "to nesmíš" se nezbývá než pozasmát. V embedded se takto programuje naprosto běžně...

V C lze psát jak portabilní kód, tak specifický kód pro nějakou architekturu. Podporuje i inline assember instrukce.

10
Vývoj / Re:Je jazyk C skutočne ťažký?
« kdy: 11. 06. 2025, 11:21:43 »
No blbě. Pokud to vaše platforma potřebuje, tak vám musí dát nějaký nestandardní způsob jak to udělat. Standardní C to neumí (pokud teda NULL odpovídá adrese 0, to taky nemusí platit).
Nesmysl. Standardní C to umí a vždy se to dělalo přes pointer, pokud jste někdy viděl nějakou knihovnu pro mikrokontroléry, tak tam se nastavují registry takto běžně, třeba AVR.

Správný postup je napsat všechno bez chyb. Jenže my lidi to jaksi neumíme. A proto tu řešíme co mi jazyk udělá, když se seknu a něco neohandlím.
Tohle není chyba, tohle je zásadní neznalost že datový typ nemůže nabývat neomezeného počtu hodnot a má horní a spodní limit. A když má horní limit a přičítám číslo 1, tak zákonitě musím operaci povolit jen v rozmezí po horní limit - 1. To je realita s kterou musí pracovat každý programátor, který má fixní datové typy, toto neplatí pouze pro C, vychází to z toho že proměnná má určitou bitovou šířku a může mapovan omezený půočet hodnot. To je základní znalost v programování.

Je to jen další "wishful programming" kde si programátor přeje aby měl něco jiného než reálně má.

Jestli někdo ani toto nemá, tak ať se C raději vyhne a nechá pracovat ty kteří tomu rozumí a umí to napsat bez chyb.

11
Vývoj / Re:Je jazyk C skutočne ťažký?
« kdy: 11. 06. 2025, 11:00:53 »
A jak zapíšu do registru který je na adrese 0x00000000
Nezapíšeš. Protože gcc ti na tohle, v závislosti na optimalizacích, verzi překladače a fázi měsíce vygeneruje ud2 isntrukci. A proč? Protože může, je to undefined behavior, norma takové chování povoluje.

https://godbolt.org/z/bGqsEqsYc

Tak překladač má být správně nastaven podle toho co dělám...
Kód: [Vybrat]
-O2 -fno-delete-null-pointer-checks
https://godbolt.org/z/TTfc87sxb

Kód: [Vybrat]
test():
        mov     DWORD PTR ds:0, 1
        ret

12
Vývoj / Re:Je jazyk C skutočne ťažký?
« kdy: 11. 06. 2025, 09:49:34 »
Proč přeháním? UB stojí na tom, že nesmí nastat. Validní C programy neobsahují UB. Programátor má za úkol zajistit aby k němu nemohlo dojít.
Dereference NULL je UB -> když dereferencuju pointer, tak optimalizátor ví, že nikdy nemůže být NULL a může tuhle informaci využít jak uzná za vhodné.
Nebo třeba funkce
Kód: [Vybrat]
bool test(int x)
{
  return x+1 > x
}
říká dvě věci :
1) + nikdy nepřeteče, takže test vždycky vrátí true. Takže z toho může optimalizátor udělat return true.
2) x nikdy nebude INT_MAX (protože by + přeteklo). Takže optimalizátor může tuhle informaci propagovat výš. Občas to může dotéct až překvapivě daleko.

Jen jsem se snažil trošku nezvyklým způsobem vystihnout tu neintuitivnost celého UB.

A jak zapíšu do registru který je na adrese 0x00000000, nebo jak si přečtu kam ukazuje reset vektor, kdyby mi to kompilátor nedovolil? Proč by mi to neměl dovolit?

Kód: [Vybrat]
bool test(int x)
{
  return x+1 > x;
}
Při x == INT_MAX výsledek přeteče a je to UB.

Správný postup je nedovolit přetečení a ohandlovat ho:
Kód: [Vybrat]
bool test(int x)
{
  return x < INT_MAX ? x + 1 > x : false; // nebo true? Co ja vim jak tento dalsi vyumelkovany nesmysl ma vypadat...
}

13
Vývoj / Re:Je jazyk C skutočne ťažký?
« kdy: 11. 06. 2025, 09:11:33 »
To, co tu tvrdíme už nějakou dobu. Nechat C jen tam, kde je to nezbytně nutné. A tam, kde chceš performance, ale není nutně důvod použít C, použít třeba Rust. Který dá +- podobný výkon, ale z principu vyloučí velmi časté chyby z C.

Proč lidi tolik trvají na tom, že i šroub musí zatlouct kladivem, jen proto, že je to o něco rychlejší, než najít ten šroubovák?  :D

Ono psát nějaké datové struktury v Rustu je celkem chuťovka. Ve standardní knihovně se k tomu používá unsafe Rust a opět vám hrozí nedefinované chování kvůli aliasingu. Navíc řešíte řešíte problémy, které v C nejsou, jako například, jak vhodně použít PhantomData.


Protože ty problémy v C jsou. Schované. Rust Vás jen donutí je explicitně pojmenovat a vyřešit.


Tady prezentovaná zásadní výhoda C - výkon a přímé napojení na hw - je i jeho zásadní nevýhodou. Překladač nemá dost informací o vysokoúrovňovém záměru a nemůže tudíž aplikovat všechny optimalizace a kontroly.

Praveze C umoznuje psat tak ci onak. Je to o tom jak si programator projekt zorganizuje.

14
Vývoj / Re:Je jazyk C skutočne ťažký?
« kdy: 10. 06. 2025, 22:22:18 »
Toto je normální runtime podtečení, proč by to mělo dávat warning?
Protože to má dát tento warning, ale z nějakého důvodu nedá. Pokračuj v řešení kvízu, jsi na dobré cestě ;)
Kód: [Vybrat]
main.c: In function ‘main’:
main.c:10:5: warning: array subscript 4294967296 is outside array bounds of ‘int[2]’ [-Warray-bounds]

Ne, k datům se přistupuje přes pointer, tak proč by to mělo psát že array out of bounds?

15
Vývoj / Re:Je jazyk C skutočne ťažký?
« kdy: 10. 06. 2025, 21:47:40 »
Další příklad "wishful programmingu". Proč máš i unsigned když chceš dělat signed aritmetiku a mít výsledek -1?
Ano, všichni víme, že ty bys žádnou podobnout chybu nikdy neudělal, ale kde je ten slibovaný warning, který měl být s -Wall vidět?

Toto je normální runtime podtečení, proč by to mělo dávat warning?

Stran: [1] 2 3 4