Portál AbcLinuxu, 12. května 2025 09:00

Dotaz: Bitový posun, UB

4.2.2016 02:30 Tonda
Bitový posun, UB
Přečteno: 541×
Odpovědět | Admin
Zajímá mě, jestli v následujícím příkladě dojde k UB při bitovém posunu. Posouvám hodnotu typu uint_least16_t o 16 bitů vlevo. Pokud je na dané platformě int 32bit a onen uint_least16_t bude typedef na 16bit unsigned short, tak pokud to správně chápu, bude uint_least16_t povýšen nejprve na int (protože může reprezentovat všechny jeho hodnoty, tak se nepoužije unsigned) a pak se provede bitový posun, který může vyvolat UB, pokud v nejvyšším bitu v původním typu byla hodnota 1, protože se posune do sign bitu)? A jak poznám, jestli vůbec o 16 bitů posunout můžu? Čtu, že nesmím posunout o stejné či vyšší počet bitů jako povýšený operand, tj. po povýšení na int bych mohl. Jde mi o to provést bitový posun o těch 16 bitů a nechat případný "zbytek" v té proměnné na platformě, kde uint_least16_t není stejný jako uint16_t, či takový typ neexistuje.
Nástroje: Začni sledovat (0) ?Zašle upozornění na váš email při vložení nového komentáře.

Odpovědi

4.2.2016 09:48 Ovrscout
Rozbalit Rozbalit vše Re: Bitový posun, UB
Odpovědět | | Sbalit | Link | Blokovat | Admin
Pokud bude uint_least16_t velké 16bitů (což je to co název typu zaručuje) tak shift do leva o 16bitů je sám o sobě UB.

Všechny další úvahy (jako že to může být větší než 16bitů) už jsou tedy ve stínu tohoto UB. Jinak řečeno,pokud budeš posunovat max o 15 (tak jak je povoleno) tak to bude fungovat správně ať už bude velký 16 nebo 32bit. A i bez ohledu na to jestli si to překladač vnitřně převede na signed int nebo ne.

Něco se dá najít třeba na www.securecoding.cert.org
4.2.2016 12:07 Tonda
Rozbalit Rozbalit vše Re: Bitový posun, UB
Problém je, že uint_least16_t nemusí mít 16 bitů, má alespoň 16 bitů a zároveň je to nejmenší takový typ. Pro případ, že je to typ větší (možná použiju místo toho i uint_fast16_t, to bude pro můj účel asi lepší), tak tam chci nechat ty původní bity, tolik, kolik můžu, a změnit jen těch spodních 16, proto posouvám o 16 místo přímého nastavení na 0 či novou hodnotu.
Do not shift an expression by a negative number of bits or by a number greater than or equal to the precision of the promoted left operand.
Já právě nevím, jestli tohle chápu dobře. Mně se zdá, že mluví už o tom povýšeném operandu (tedy v mém případě by to už byl int, na který bude uint_least16_t povýšen, na jiné platrmě, kde int je 16bit povýšen nebude, to je taky problém). Jak nejlépe vyřešit tuto situaci, aby nedocházelo k UB?
4.2.2016 13:17 Ovrscout
Rozbalit Rozbalit vše Re: Bitový posun, UB
Mno jediné co mne napadá je posouvat o těch 16bitů jen když víš že ten typ je opravdu větší. Vzhledem k tomu že se chceš chovat podle velikosti na konkrétní platformně tak je třeba udělat podmínku. Takhle od boku mne napadají dvě varianty(netestováno jen píšu od boku):

A)porovnáním počtu bitů (pokud nepoužíváš optimalizace tak bude tento kód pomalejší, navíc může překladač hlásit warningy že podmínka je vždy true/false:
#include "limit.h"
if (sizeof(a)*CHAR_BIT>16)
{
  a=a<<16;
}else
{
  a=0;
}
B)nebo podmíněným překladem, trošku čistější z hlediska generovaného kódu ale někomu se podmíněný překlad nelíbí.
#include "stdint.h"
#ifdef UINT_LEAST16_MAX > 65535
  a=a<<16;
#else
  a=0;
#endif

p.s. include nema mit uvozovky ale znamenko vetsi mensi ale nejak mi to zdejsi forum nechce pustit
4.2.2016 13:23 Michal Kubeček | skóre: 72 | Luštěnice
Rozbalit Rozbalit vše Re: Bitový posun, UB
p.s. include nema mit uvozovky ale znamenko vetsi mensi ale nejak mi to zdejsi forum nechce pustit

Je potřeba je zapsat entitami &lt; resp. &gt; (což udělají tlačítka "<" a ">" nad formulářem).

4.2.2016 13:50 Tonda
Rozbalit Rozbalit vše Re: Bitový posun, UB
B bude asi ideální. Děkuji.
Voty avatar 4.2.2016 14:18 Voty | skóre: 12 | blog: gemini
Rozbalit Rozbalit vše Re: Bitový posun, UB
Asi nejjednodušší varianta je

uint_least16_t x;

x <<= 8U; x <<= 8U;

Optimalizují překladač by to mohl přeložit i docela rozumně. Např. gcc při O2 nahradí posuny XORem registru pro uint16_t a shiftem o 16 pro uint32_t.
Jednu rozbil a tu druhou ztratil.
4.2.2016 18:33 Radek
Rozbalit Rozbalit vše Re: Bitový posun, UB
Odpovědět | | Sbalit | Link | Blokovat | Admin
Ono je to takto

int a;
short i; //minimalne 16b
a = i << 16; // může delat chybu, pokud bude short 16b
a = ((int) i) << 16; // je v poradku
4.2.2016 19:48 Tonda
Rozbalit Rozbalit vše Re: Bitový posun, UB
To by myslím nešlo, když int bude stejně velký jako short a budou těch minimálních 16b. Náš profesor je na nás strašně přísný a co standard negarantuje, to nesmíme předpokládat. Úlohy spouští v emulátorech různých architektur a když mu to na jedné nejde, tak dá nedostatečnou. Má tam i nějaké zvrhlosti, kde je char 9 bitů apod.
4.2.2016 20:59 Michal Kubeček | skóre: 72 | Luštěnice
Rozbalit Rozbalit vše Re: Bitový posun, UB
Takže on je to domácí úkol, ne skutečný problém? :-( Teď už se nedivím, že mi to zadání od začátku připadalo podezřele umělé…
4.2.2016 23:04 Radek
Rozbalit Rozbalit vše Re: Bitový posun, UB
Omlouvám se zapomnel jsem ze int muze byt 16b. použi místo toho long, ten je minimálně 32.
kozzi avatar 5.2.2016 12:24 kozzi | skóre: 55 | blog: vse_o_vsem | Pacman (Bratrušov)
Rozbalit Rozbalit vše Re: Bitový posun, UB

Kdyby radsi ucil lepsi jazyky kde tyto problemy neexistuji :D

Linux je jako mušketýři "jeden za všechny, všichni za jednoho"
6.2.2016 05:08 Jardík
Rozbalit Rozbalit vše Re: Bitový posun, UB
Třeba D, že? Potřeboval jsem nedávno dělat CRC32 nad spoustou dat ... knihovní implementace pomalá. Ručně napsaná taky pomalá (optimalizace + bez kontroly indexů, bez alokací). Pak jsem zkusil napsat v C. Místo 15 minut to trvalo jen 5. A pak jsem ještě vyhodil DMD a přejel to LDC. Výsledek byl jen asi o minutu horší než C.
kozzi avatar 7.2.2016 18:30 kozzi | skóre: 55 | blog: vse_o_vsem | Pacman (Bratrušov)
Rozbalit Rozbalit vše Re: Bitový posun, UB

Tak to je nekde neco spatne stejny kod v C a v D by mel byt vetsinou skoro uplne stejne vykony. Snad nikdy jsme nedosahl nijak horsiho vykonu. Samozrejme je potreba srovnavat GDC a GCC, pripadne clang ldc nebo dmc a dmd.

Linux je jako mušketýři "jeden za všechny, všichni za jednoho"

Založit nové vláknoNahoru

Tiskni Sdílej: Linkuj Jaggni to Vybrali.sme.sk Google Del.icio.us Facebook

ISSN 1214-1267, (c) 1999-2007 Stickfish s.r.o.