Typy v C++

Jan Waclawek konfera na efton.sk
Sobota Leden 15 10:20:28 CET 2022


> 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>

_______________________________________________
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



Další informace o konferenci Hw-list