Typy v C++

Jindroush jindroush na seznam.cz
Sobota Leden 15 10:54:31 CET 2022


--Wall --Wextra --pedantic --Werror ;)
Tady je sice clanek, ktery je proti Werror, ale pridavam ho jako 
zamysleni, protoze radsi budu "predem" resit, jake jsou potencialni 
problemy, nez na realnem hw resit, proc to dela pankacoviny.
https://embeddedartistry.com/blog/2017/05/22/werror-is-not-your-friend/

Jinak co vece wek o printf/scanf - ano, na "malych" architekturach 
nemaji opodstatneni (ono taky nekdy staci pohled do mapfajlu, kolik 
zerou) a na vetsinu pouziti existuji jednodussi funkce. Co se tyce 
scanfu, mam z nej blby pocit i na 'velkych' targetech, takze jsem ho 
snad nikdy nepouzil a prasim si input jinak - nebo idealne pouzit 
knihovnu nad "rozumnym" input formatem. (Rozumny je v uvozovkach protoze 
podleha vyhodnoceni ktereho toho soudruha).

PS: Ten priklad s tim makrem Log nedava takto smysl, anzto i kdyby bylo 
makro Log prazdne, stejne je tam strednik, takze v efektu je to "if( 
zapis );", coz zpusobi v nekterych prekladacich warning, ale nema to ten 
popisovany vedlejsi efekt.

J.

On 15.01.2022 10:40, Michal Gregor wrote:
> Tak MISRA neni zbytecna. Ono to ignorrovani warningu se dost vymsti:
>
> uint16_t Teplota;
> uint8_t TeplotaZobrazena;
> TeplotaZobrazena = Teplota;
> Prekladac tam samozrejme dal warning, ale vsichni na to kaslali. A pak 
> se hledala chyba asi dva dny.
> Krome toho TeplotaZobrazena je pouze Fahrenheita ale Teplota muze byt 
> i v celsiech.
>
> Nebo tohle
> if (zapis)
>     Log(teplota);
> teplota = teplota + 23;
>
> Dalsich par dni zabitych, kvuli lenosti. Log neni funkce, ale makro, 
> ktere funguje pouze v debug verzi. Takze se radek teplota = teplota + 
> 23; ignoroval.
>
> Spravne to ma byt:
> if (zapis)
> {
>     DEBUG_LOG(teplota);
> }
>
>
>
> Michal Gregor
>
>
> Dne 15.01.2022 v 10:20 Jan Waclawek napsal(a):
>>> No a já mám nepìkné pocity z celého C, tím se øídit nemù¾u :)
>>
>> Tak su dve cesty: bud budete ten pocit ignorovat, ako to robi 99.9%
>> normalnych programatorov, alebo stravite strasne vela casu skumanim
>> nechutnych podrobnosti, vratane citania (ci dokonca pisania) "skutocnej
>> dokumentacie" (t.j. zdrojovych textov prekladacov a kniznic) a
>> normativnych materialov... a toto moze robit iba blazon... ;-)
>>
>> Warningy, ktore do gcc pribudli niekedy po roku 2010, nevychadzaju z
>> poziadaviek jazyka/normy, ale skor z predstavy, ze existuju jednoduche
>> pravidla, ktorych dodrziavanie znizuje chybovost programov. Je to ta 
>> ista
>> predstava ktora motivuje aj predpisy typu MISRA; bohuzial je to zalozene
>> len na pocitoch autorov, bez akychkolvek realnych dokazov. Ale to je na
>> pivnu debatu.
>>
>> Konkretne tu gcc priamo napovie, cim bol dany warning zapnuty
>>> int*'} [-Wformat=]
>> a tento prepinac je popisany samozrejme v manuali
>> https://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html#index-Wformat
>> (treba zarolovat dva riadky nahor)
>> cize sa jedna o warning specificky pre rodinu printf()/scanf() prip.
>> kniznicne funkcie specialne oznacene v zdrojovom texte danej kniznice.
>>
>> V dalsom budem hovorit len o C, pretoze C++ nepoznam, a C++ *je* iny 
>> jazyk
>> ako C (v tomto kontexte by mohlo byt zaujimave skusit prelozit
>> inkriminovany riadok ako C).
>>
>> Napriek tomu, ze ich interna reprezentacia je identicka, 'unsigned 
>> int' je
>> *iny typ* nez 'unsigned long int', a uint32_t je typedef-ovany (co v 
>> C ma
>> len slaby vyznam, znamena to len premenovanie) v tomto konkretnom
>> prekladacom prostredi specificky ako unsigned long int. V inych
>> prekladacich prostrediach to moze byt inak (dokonca aj keby islo o 
>> gcc pre
>> Cortex-M, kedze tento typedef je dany v <stdint.h>, t.j. v standardnej
>> kniznici a nie v kompilatore). Ale v dalsom berme, ze uint32_t je rovny
>> unsigned long int.
>>
>> Pri volani funkcie v C sa na parametroch ako prve urobia implicitne
>> konverzie. Takze ak mame funkciu, ktora vyzaduje smernik na unsigned 
>> int,
>> a dame mu smernik na uint32_t, dojde k implicitnej konverzie medzi 
>> tymito
>> smernikmi. Su to smerniky na rozne typy, a na takuto konverziu podla
>> 6.3.2.3 nie su kladene ine podmienky ako spravne zarovnanie v pamati, 
>> a ak
>> je interna reprezentacia bazovych typov v oboch pripadoch rovnaka, 
>> tak aj
>> dereferencovanie konvertovaneho smernika dopadne ocakavanym sposobom. Ak
>> by tie interne reprezentacie boli odlisne, prekladac sice nemusi urobit
>> nic zle, ale tam je warning opravneny.
>>
>> Lenze u printf()/scanf() sa situacia komplikuje tym, ze sa jedna o 
>> funkcie
>> s variabilnymi parametrami, t.j. v prototype je za formatovacim retazcom
>> '...'. Kedze variabilna cast parametrov sa vyhodnocuje az pri behu
>> programu, prekladac vo vseobecnosti nema sancu ich skontrolovat. 
>> Kedze sa
>> vsak jedna o standardardnu kniznicu, gcc ma rozsirenie, ktorym si
>> zinterpretuje formatovaci retazec rovnako ako by ho mala interpretovat
>> samotna printf()/scanf() funkcia, a na zaklade toho tie parametre
>> kontroluje - toto rozsirenie je riadene prave tym -Wformat-om. Tato
>> kontrola je vsak uz ina, nez ta, ktoru robi prekladac pri kontrole
>> parametrov "normalnych" funkcii, proste ma svoje pravidla, a tie dva
>> smerniky sa vyhodnotia ako odlisne a vypise sa chyba. Ako vravim, 
>> warningy
>> su viacmenej vecou individualnych rozhodnuti silno argumentujucich
>> jedincov, a tato "zvysena prisnost" je rozhodnutie toho, kto to 
>> rozsirenie
>> pisal. Mozno na to existuju nejake dobre argumenty, ja neviem.
>>
>> Takze ako z toho von:
>>
>> - vypnut tu kontrolu, tj. pouzit -Wno-format, ci uz lokalne pre danu
>> funkciu (s pouzitim prislusnej #pragma, nechce sa mi to hladat) alebo v
>> prikazovom riadku pre cely subor
>>
>> - pouzit modifikovany specifikator (ano! :-)  %lX ako to navrhuje
>> prekladac, co vyuziva fakt ze v tomto prekladacom prostredi uint32_t ==
>> unsigned long int (t.j. je to neprenosne)
>>
>> - pouzit specifikator PRIu32 specificky pre uint32_t podla <inttypes.h>
>> printf("%" PRIu32 "\n",a); - toto je prenosne ale esteticky nepekne...
>>
>> - explicitne pretypovat na typ, ktory chcem vytlacit - kedze podla normy
>> specifikator X je specificky pre unsigned int, tak 
>> printf("%X\n",(unsigned
>> int)a);
>>
>> - nepouzit printf()/scanf(), lebo [slovo do bitky] printf()/scanf() 
>> do mcu
>> nepatria [/slovo do bitky] - ako Jindroush pisal, v tomto pripade je
>> vhodnejsie pouzit strtoul()
>>
>> wek
>>
>>
>>
>> ----- Original Message ---------------
>>
>> Subject: Re: Typy v C++
>>     From: "Pavel Kutina" <hw na prelude.cz>
>>     Date: Fri, 14 Jan 2022 17:32:52 +0100
>>       To: "HW-news" <hw-list na list.hw.cz>
>>
>> Mo¾ná by to lep¹í bylo - tedy nebýt toho, ¾e ho neznám, a ¾e kolega 
>> pøi¹el
>> s
>> tím ¾e "to se øe¹ilo támhle v XXXX.c, tak to napi¹ podle toho."
>>
>> No a já mám nepìkné pocity z celého C, tím se øídit nemù¾u :)
>>
>> Pavel Kutina
>>
>>
>>
>> ----- Original Message -----
>> From: "Jindroush" <jindroush na seznam.cz>
>> To: "HW-news" <hw-list na list.hw.cz>
>> Sent: Friday, January 14, 2022 5:19 PM
>> Subject: Re: Typy v C++
>>
>>
>> Ale ten komplikator tam napovida, ze misto %X pouzit treba %lX a je
>> vymalovano.
>> Ostatne, nebylo by lepsi pouzit strtoul, ja mam z toho sscanfu vzdycky
>> takovy nepekny pocity?
>> J.
>>
>> On 14.01.2022 17:12, Pavel Kutina wrote:
>>> U¾ jsem to dohledal:
>>>
>>> ////unsigned int cnt = 0; // tohle je bez výhrad
>>> uint32_t cnt = 0;
>>> sscanf(pData, "%X", &cnt);
>>>
>>> ../src/receive.cpp:117:19: warning: format '%X' expects argument of 
>>> type
>>> 'unsigned int*', but argument 3 has type 'uint32_t*' {aka 'long 
>>> unsigned
>>> int*'} [-Wformat=]
>>> 117 | sscanf(pData, "%X", &cnt);
>>> | ~^ ~~~~
>>> | | |
>>> | | uint32_t* {aka long unsigned int*}
>>> | unsigned int*
>>> | %lX
>>>
>>>
>>> Pokud to deklaruju jako 16bit:
>>>
>>> uint16_t cnt = 0;
>>> sscanf(pData, "%X", &cnt);
>>>
>>> ../src/receive.cpp:117:19: warning: format '%X' expects argument of 
>>> type
>>> 'unsigned int*', but argument 3 has type 'uint16_t*' {aka 'short 
>>> unsigned
>>> int*'} [-Wformat=]
>>> 117 | sscanf(pData, "%X", &cnt);
>>> | ~^ ~~~~
>>> | | |
>>> | | uint16_t* {aka short unsigned int*}
>>> | unsigned int*
>>> | %hX
>>>
>>>
>>> Jinak to je pro STM32L471, máme je¹tì pár kouskù "z pøedváleèných 
>>> zásob".
>>>
>>> Pavel Kutina
>>>
>>>
>>> ----- Original Message ----- From: "Tomá¹ Hamouz"
>>> <konfery.tomas.hamouz na seznam.cz>
>>> To: "HW-news" <hw-list na list.hw.cz>
>>> Sent: Friday, January 14, 2022 5:01 PM
>>> Subject: Re: Typy v C++
>>>
>>>
>>> A nebyl to pointer na unsigned? Pokud bys tam strèil *uint16_t tak by
>>> do¹lo k pøepsání dat.
>>>
>>> Jinak délka int a unsigned int jsou implementaènì závislé, musí jen
>>> platit ¾e
>>>
>>> sizeof(short) <= sizeof(int) <= sizeof(long)
>>>
>>> V¹imni si ¾e short mù¾e být stejnì dlouhý jako long a bude to podle
>>> normy ;-)
>>>
>>> Tomá¹
>>>
>>>
>>>
>>>> No nezbývá, ne¾ se nauèit dávat si na to bacha :(
>>>
>>>> A ten rozdíl mezi unsigned int a uint16_t (uint8_t, uint32_t atd.) 
>>>> taky
>>>> nìkdo umíte vysvìtlit? Vyøval mne sscanf a tam jsem tio vzdal a
>>>> pøíslu¹nou
>>>> promìnnou deklaroval jako unsigned int (bohu¾el pøslu¹ná èást kódu 
>>>> pro¹la
>>>> demolicí, teï to nedoká¾u zrekonstruovat).
>>>
>>>> Jinak jaké je doporu¹ení? Pro mne je deklarace pøes ty pøetypované _t
>>>> pøehlednìj¹í, ale nejspí¹ to nemusí být v¾dycky toté¾.
>>>
>>>> Pavel Kutina
>>>
>>>
>>>> ----- Original Message ----- From: "Jindroush" <jindroush na seznam.cz>
>>>> To: "HW-news" <hw-list na list.hw.cz>
>>>> Sent: Friday, January 14, 2022 4:30 PM
>>>> Subject: Re: Typy v C++
>>>
>>>
>>>> odpoved uz dosla s vysvetlenim... Jinak jsem to nacpal do
>>>> https://cppinsights.io/
>>>
>>>> a zaskrtl, at ukaze implicitni konverze, tam je to videt na vlastni 
>>>> voko
>>>> if((static_cast<unsigned int>(static_cast<int>(LastCounter) + 1)) 
>>>> == cnt)
>>>> {
>>>
>>>> On 14.01.2022 16:13, Pavel Kutina wrote:
>>>>> Zdravím,
>>>>>
>>>>> opìt nìco nechápu, mù¾ete mne po¹touchnout?
>>>>>
>>>>> Pí¹u FW v STM Cube, mám deklarované dvì promìnné:
>>>>>
>>>>> unsigned int cnt = 0;
>>>>> uint16_t LastCounter = 0;
>>>>>
>>>>> pøi porovnání v:
>>>>>
>>>>> if (LastCounter+1 == cnt)
>>>>>
>>>>> mi to pí¹e warning:
>>>>> ../src/receive.cpp:129:22: warning: comparison of integer 
>>>>> expressions of
>>>>> different signedness: 'int' and 'unsigned int' [-Wsign-compare]
>>>>> 129 | if ( (LastCounter+1) == cnt)
>>>>> | ~~~~~~~~~~~~~~^~~~~~
>>>>>
>>>>> Chápu dobøe, ¾e unsigned int a uint16_t nejsou znaménkovì 
>>>>> kompatibilní
>>>>> typy? Proè ne?
>>>>>
>>>>> Na nìco podbného jsem narazil pøed chvílí u sscanf, kde se mi to zase
>>>>> vztekalo pri pou¾ití uint16_t (jsem tam mìl) místo unsigned int 
>>>>> (který
>>>>> to
>>>>> chtìlo).
>>>>>
>>>>> Popravdì, asi 90% èasu tohoto projektu trávím rovnáním datových typù,
>>>>> hodne v tom plavu :(
>>>>>
>>>>> Díky.
>>>>>
>>>>> Pavel Kutina
>>>>>
>>>>> _______________________________________________
>>>>> HW-list mailing list - sponsored by www.HW.cz
>>>>> Hw-list na list.hw.cz
>>>>> http://list.hw.cz/mailman/listinfo/hw-list
>>>
>>>
>>> _______________________________________________
>>> HW-list mailing list - sponsored by www.HW.cz
>>> Hw-list na list.hw.cz
>>> http://list.hw.cz/mailman/listinfo/hw-list
>>> _______________________________________________
>>> HW-list mailing list - sponsored by www.HW.cz
>>> Hw-list na list.hw.cz
>>> http://list.hw.cz/mailman/listinfo/hw-list
>>
>>
>

-- 
Jindroush <jindroush na seznam.cz>



Další informace o konferenci Hw-list