Pretypovani ukazatele struktury na bajt

Josef Štengl ok1ced na nagano.cz
Úterý Únor 25 16:56:52 CET 2020


To je důsledek implicitních konverzí. Jsem líný to popisovat a musel bych to dohledávat, jestli jsem se nespletl, tak se 
spoléhám na weka, že to vysvětlí :-)

Posuny, jsou závislé na architektuře. Některé architektury mají pouze beznaménkové, některé obojí. Proto se posuny nad 
znaménkovými čísly nebo typy obecně nedoporučují. Nejlepší se je na to ... a posuny provádět pouze nad unsigned proměnnými 
nebo čísly.


Dne 25. 02. 20 v 16:34 David Obdrzalek napsal(a):
> Jo, když se to důsledně otypuje, tak to pak je lepší, to mi je jasný :-)
> 
> Nerozumím ale tomu, že 0xADDE přiřazeno do 32bit unsigned se roztáhne do 32bit
> unsigned bez znamínka (zde implicitně), ale 0xDE se po posunutí o 8 doleva a pak
> přiřazení do 32bit unsigned (opět implicitně) roztáhne znamínkově.
> Pokus:  hdr.ident = (uint32_t)(0xAD << 8); // přiřadí se 0xFFFFAD00
> zatímco hdr.ident = (uint32_t)(0xAD00);    // přiřadí se 0x0000AD00
> Zrada se tedy zdá být v chování toho shiftu.
> 
> Ale to s tím hextem že je vždy znamínkový se mi nějak nezdá, měl jsem za to, že ten
> postup je "když se vejde do int tak int, když ne, tak unsigned int, když ne, tak
> long int atd.". Jo a to by asi sedělo - 0xAD se vešlo do int, tedy je signed a
> rozšíření na 32bit je signed a nějak se to tam pomele. 0xAD00 se nevešlo do int,
> ale do unsigned int jo, takže je unsigned a tedy rozšíření na 32bit je unsigned bez
> ztráty kytičky. Kdybych napsal rovnou 0xADu, tak si vynutím unsigned a dál to už
> známe.
> 
> Malinko mi tam lavíruje to, že se shiftem o 8 stalo z 0x00AD (což byl kladný int)
> něco záporného, ale třeba je to jen nedefinované (tj. shift intu tak, že se do intu
> nevejde) a shodou náhod to je takhle. No a to teď ověřil pokus, shift doleva se
> zjevně v mém avr-gcc dělá naprosto jednoduše tak, že se to prostě shiftne bez
> ohledu na znamínko a když zrovna ve výsledku padne jednička do nejvyššího bitu, no
> tak máme záporné číslo :-)
> hdr.ident = (uint32_t)(0xAD << 7) ... 00005680 = 16 nul      a 01010110 10000000
> hdr.ident = (uint32_t)(0xAD << 8) ... FFFFAD00 = 16 jednicek a 10101101 00000000
> hdr.ident = (uint32_t)(0xAD << 9) ... 00005A00 = 16 nul      a 01011010 00000000
> hdr.ident = (uint32_t)(0xAD << 10)... FFFFB400 = 16 jednicek a 10110100 00000000
> hdr.ident = (uint32_t)(0xAD << 11)... 00006800 = 16 nul      a 01101000 00000000
> hdr.ident = (uint32_t)(0xAD << 12)... FFFFD000 = 16 jednicek a 11010000 00000000
> hdr.ident = (uint32_t)(0xAD << 13)... FFFFA000 = 16 jednicek a 10100000 00000000
> hdr.ident = (uint32_t)(0xAD << 14)... 00004000 = 16 nul      a 01000000 00000000
> 
> Hurá :-)
> 
> A podle toho bych si tipnul, že shift doleva záporného intu uloženého zase do intu
> je nedefinovaný, ale prakticky se prostě shiftne a vznikne něco kladného nebo
> záporného podle toho, jestli do nejvyššího bitu padla 0 nebo 1.
> 
> D.O.
> 
> 
> On 25 Feb 2020 at 15:15, Josef Štengl wrote:
>> Hmm. Protože se při posunu před tím provede typová konverze. Zkuste si, co to
>> udělá, když napíšete u (jako unsigned) za
>> 0xAD. Hexadecimální číslo bez u je bráno jako signed. U dekadických to
>> neplatí, to může být signed nebo unsigned podle
>> kontextu, pokud není uvedeno u na konci nebo přetypováno.
>>
>> Pro eliminaci takových to záhad je vhodné čísla důsledně přetypovávat,
>> pokud jsou uveden v aritmetických operacích. Má to
>> svoji logiku ale kdo by si ji pamatoval. A většina té logiky je závislá na
>> implementaci.
>>
>>
>>
>> Dne 25. 02. 20 v 15:01 David Obdrzalek napsal(a):
>>> Ale proč to funguje s 0xADDE, které má taky nejvyšší bít nahozený?
>>>
>>> D.O.
>>>
>>> On 25 Feb 2020 at 13:58, Hynek Sladky wrote:
>>>> To vypada na znamenko...
>>>> 0xAD << 8 je 16-bitovy int se zapornou hodnotou
>>>> Pak se to implicitne pretypuje na uint32_t (podle dalsich clenu), ale
>>>> protoze to je zaporna hodnota, tak se znamenko expanduje do vyssich bytu
>>>> jako 0xFFFF0000.
>>>>
>>>> Mohlo by pomoct zapisovat konstanty s priponou u, tedy napr. 0xADu << 8
>>>>
>>>> Hynek Sladky
>>>>
>>>>
>>>> Dne 25.2.2020 v 13:28 David Obdrzalek napsal(a):
>>>>> ALE když odmažu přetypování prvních dvou bytů, tak tam vyjde:
>>>>> hdr.ident = 0xDE | 0xAD << 8 | ((uint32_t)0xBE) << 16 | ((uint32_t)0xEF) <<
>> 24;
>>>>>     4c6:	8e ed       	ldi	r24, 0xDE	; 222
>>>>>     4c8:	9d ea       	ldi	r25, 0xAD	; 173
>>>>>     4ca:	af ef       	ldi	r26, 0xFF	; 255
>>>>>     4cc:	bf ef       	ldi	r27, 0xFF	; 255
>>>>>     4ce:	80 93 b1 01 	sts	0x01B1, r24	; 0x8001b1 <hdr+0x2>
>>>>>     4d2:	90 93 b2 01 	sts	0x01B2, r25	; 0x8001b2 <hdr+0x3>
>>>>>     4d6:	a0 93 b3 01 	sts	0x01B3, r26	; 0x8001b3 <hdr+0x4>
>>>>>     4da:	b0 93 b4 01 	sts	0x01B4, r27	; 0x8001b4 <hdr+0x5>
>>>>>
>>>>> Vůbec nachápu, proč ty dvě FF ??
>>>>>
>>>>> hdr je deklarované takhle:
>>>>> typedef struct {
>>>>>      uint16_t magic;
>>>>>      uint32_t ident;
>>>>> } _hdr;
>>>>> _hdr hdr;
>>>>>
>>>>> Překladač avr-gcc (GCC) 5.4.0 na Win.
>>>>>
>>>>>
>>>>> Jo tak teď jsem ještě zmatenější, protože mě napadlo zkusit:
>>>>> hdr.ident = 0xADDE | ((uint32_t)0xBE) << 16 | ((uint32_t)0xEF) << 24;
>>>>>     4c6:	8e ed       	ldi	r24, 0xDE	; 222
>>>>>     4c8:	9d ea       	ldi	r25, 0xAD	; 173
>>>>>     4ca:	ae eb       	ldi	r26, 0xBE	; 190
>>>>>     4cc:	bf ee       	ldi	r27, 0xEF	; 239
>>>>>     4ce:	80 93 b1 01 	sts	0x01B1, r24	; 0x8001b1 <hdr+0x2>
>>>>>     4d2:	90 93 b2 01 	sts	0x01B2, r25	; 0x8001b2 <hdr+0x3>
>>>>>     4d6:	a0 93 b3 01 	sts	0x01B3, r26	; 0x8001b3 <hdr+0x4>
>>>>>     4da:	b0 93 b4 01 	sts	0x01B4, r27	; 0x8001b4 <hdr+0x5>
>>>>>
>>>>> a tohle prošlo jak bych původně čekal!
> 
> 
> _______________________________________________
> 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