Pretypovani ukazatele struktury na bajt

David Obdrzalek David.Obdrzalek na mff.cuni.cz
Úterý Únor 25 16:34:34 CET 2020


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!




Další informace o konferenci Hw-list