zakerna zahada GCC

Petr Labaj labaj na volny.cz
Středa Únor 7 22:26:01 CET 2018


Vím, že by to nemělo mít vliv, ale stejně bych ty 2 podmínky zkusil 
ozávorkovat.

PL

************************

Dne 7.2.2018 v 21:32 Jaroslav Buchta napsal(a):
> No ja to chapu tak, ze se vyrazy vyhodnocuji zleva doprava a pokud je 
> test na hodnotu prvni, tak se provede. Asi podobne, jako se bezne pise 
> napr.: if (s != NULL && s[x] != 0).... Coz mi bylo dlouho proti srsti 
> ale zrejme to odpovida pravidlum.
> Ale tohle me fakt prekvapilo, samozrejme je to chybny zapis ale pri 
> respektovani zapisu vyrazu by nevedl k chybne funkci programu, pri 
> prekroceni rozsahu pole jsem predpokladal ze je  hodnota v danem miste 
> pameti nevyznamna, nelogicke vynechani casti podminky pak vedlo k 
> chybne funkci.
>
> Dne 07.02.2018 v 21:11 Jindroush napsal(a):
>> Je mozno si to vyzkouset:
>> https://godbolt.org/
>> x86-64, -m32 -O99 -Wall
>>
>> #include <cstdlib>
>>
>> char  text[19];
>> char text2[19];
>>
>> int main()
>> {
>>   for( size_t idx = 0; text[idx]!=0 && idx < sizeof( text ); idx++)
>>   {
>>     text2[idx]=text[idx];
>>   }
>> }
>>
>> Opravdu tu druhou podminku eliminuje a uplne tomu vysvetleni nerozumim.
>> Kdyby idx<sizeof(text) bylo vzdy true, tak bych tomu rozumel. Protoze 
>> podle normy idx smi legalne nabyvat pouze hodnot mezi 0 az 
>> sizeof(text)-1, tak skutecne podminka je vzdy true a smi se eliminovat.
>> Ale to by prece platilo i pro ten opacny pripad, kdy ji napisu jako 
>> prvni?
>>
>> J.
>>
>> On 7.2.2018 18:26, Jan Waclawek wrote:
>>> Kuzelne.
>>>
>>> Dovod ste uviedli hned na zaciatku:
>>>
>>>> Uz vim, ze je to v principu spatne a prvni cast si sahne mimo
>>>> rozsah pole, ale ze by to prekladac poresil takto?
>>>
>>> Moze, pretoze nasledok je nedefinovane spravanie. A co nie je 
>>> zakazane, je
>>> dovolene; a nerobit nieco, co netreba, je optimalne... ;-)
>>>
>>> V tomto konkretnom pripade je to nasledok poslednej vety C99 6.5.6#8 
>>> (co
>>> spolu s nasledujucim odstavcom je definicia toho co bezne nazyvame
>>> smernikova aritmetika, a ktora je tu aplikovana vdaka tomu ze v C
>>> neexistuju polia, 6.5.2.1#2):
>>>
>>> If the result points one past the last element of the array object, it
>>> shall not be used as the operand of a unary * operator that is 
>>> evaluated.
>>>
>>> (slovicko "shall" tu vedie kvoli 4#2 na nedefinovane spravanie)
>>>
>>> To "one past" je taka kuriozita, ktora dovoluje smerniku nadobudat 
>>> hodnotu
>>> 1 za polom. Tym sa dovoluje optimalizujuci postinkrement po pristupe k
>>> prvku pola v cykle. Nesmie sa samozrejme takyto smernik dereferencovat,
>>> ale moze sa pouzit napriklad na porovnanie alebo sa moze 
>>> dekrementovat (co
>>> zase dovoluje predekrement pri opacnom cykle). (Musite samozrejme 
>>> zabudnut
>>> na naivnu predstavu ze hodnota smernika *je* cislo, a uz vobec nie 
>>> adresa.
>>> Moze byt, ale nemusi - a norma predpisuje vseobecne spravanie, nie 
>>> nejaku
>>> jednu konkretnu implementaciu, co je vlastne zaruka portability. 
>>> Moze to
>>> byt ciste hardwarovo implementovane, s hardwarovou implementaciou 
>>> ochran
>>> proti vylezeniu z pola. Do urcitej obmedzenej miery nieco take MMU 
>>> vlastne
>>> robi.).
>>>
>>> Bezne ukazanie niekam uplne mimo pola vseobecne riesi popis 
>>> operatora * v
>>> 6.5.3.2#4:
>>> If an invalid value has been assigned to the pointer, the behavior 
>>> of the
>>> unary * operator is undefined.
>>>
>>> Mimochodom, zaujimalo by ma, ci bol vypisany nejaky suvisiaci warning,
>>> najma v suvislosti s -Warray-bounds (pripadne ak sa jedna o novsiu 
>>> veriu
>>> gcc, tak -Warray-bounds=2
>>> https://gcc.gnu.org/onlinedocs/gcc-7.3.0/gcc/Warning-Options.html#index-Warray-bounds 
>>>
>>> )
>>>
>>> wek
>>>
>>>
>>> PS.
>>>> definuj text[19] ako volatile,
>>> Nie, to tu nemusi pomoct, lebo pre tuto "optimalizaciu" prekladac
>>> nepotrebuje poznat *hodnotu* prvku z pola, kedze vopred *vie*, ze 
>>> citanie
>>> z nej ma nedefinovany nasledok, pretoze to uz nie je prvok pola.
>>>
>>> *Moze* to pomoct, lebo sa bavime o nedefinovanom spravani, ale nemusi.
>>>
>>> Ale mas pravdu, vhodne nastavene volatile pomoze: celkom iste pomoze
>>> kvalifikovat idx ako volatile, pretoze vtedy prekladac nemoze 
>>> vediet, aku
>>> hodnotu ma idx na zaciatku toho porovnania, a teda akakolvek
>>> "nedefinovanost" spravania je mimo moznosti detekcie kompilatorom a je
>>> dana uz len konkretnym hardwarom, na ktorom to pobezi.
>>>
>>>
>>>
>>>> Am 07.02.2018 um 17:09 schrieb Jaroslav Buchta:
>>>>> Me jde o pripad, kdy je leva podminka splnena a idx uz ma hodnotu
>>>>> treba 19, 20... coz podminku nesplnuje (pokud jsem neco neprehlednul)
>>>>> a iterace se provede. Dle disassebleru neni druha cast podminky vubec
>>>>> zohlednena, testuje se jen znak v retezci na 0.
>>>>> Kopirovani tady musim provadet po znaku, pridavaji se do dynamicky
>>>>> alokovaneho pole s nejakou inteligenci a tady neni kvalt.
>>>>> S dosazenim funkcnosti si poradim, spis si to potrebuju vysvetlit,
>>>>> tento problem se muze vyskytnout i jindy a jinde.
>>>>>
>>>>> Dne 07.02.2018 v 16:15 Jindroush napsal(a):
>>>>>> Dobry den,
>>>>>> nejsem si ted jist, jestli jsem pochopil spravne problem, ale podle
>>>>>> mne mluvite o vlastnosti C, tj. short-circuitingu AND operatoru.
>>>>>> Staci vyhodnotit levou cast a jde se dal, na poradi podminek zalezi.
>>>>>> To je dulezite si uvedomit i u funkci, ktere maji vedlejsi efekty.
>>>>>>
>>>>>> Jinak ten vas kod nezaruci zero-termination, nebo ano?
>>>>>>
>>>>>> Fungovat v debugu by to nemelo, jen to nesletelo, protoze tam byla
>>>>>> jinak a jinde alokovana pamet.
>>>>>>
>>>>>> Co vam brani pouzit bezpecnou knihovni alternativu - strlcpy?
>>>>>> (Pripadne ji nekde obslehnout).
>>>>>>
>>>>>> J.
>>>>>>
>>>>>> On 7.2.2018 14:56, Jaroslav Buchta wrote:
>>>>>>> Mam datovy typ:
>>>>>>>
>>>>>>> typedef union
>>>>>>> {
>>>>>>>       struct {
>>>>>>>           uint8_t b[32];
>>>>>>>       } ba;
>>>>>>>
>>>>>>>       struct {    //common all records (chained records exception)
>>>>>>>           uint32_t id;            // id MSb == 0
>>>>>>>           uint32_t tstp[2];
>>>>>>>       }cmn;
>>>>>>>
>>>>>>>       struct {    //Text Single or Start Record
>>>>>>>           uint32_t id;            // id MSb == 0
>>>>>>>           uint32_t tstp[2];        //timestamp in miliseconds, 
>>>>>>> record
>>>>>>> type FLCLOG_RT_* at 4 MSbs
>>>>>>>           uint8_t  sendRq;        //send to server request
>>>>>>>           uint8_t  text[19];    //content, max length
>>>>>>>       }recTxt;
>>>>>>>
>>>>>>> ...
>>>>>>>
>>>>>>> }FLCLOGRECORD;
>>>>>>>
>>>>>>> Pokud napisu podminku
>>>>>>>
>>>>>>> for (int idx=0; rec.recTxt.text[idx] != 0 && idx <
>>>>>>> sizeof(rec.recTxt.text); idx++)
>>>>>>>
>>>>>>> tak se to vykasle na druhou cast a index klidne leze na 19 a vic
>>>>>>> dokud neni v pameti nahodou nula (kopiruje to strin ktery muze ale
>>>>>>> nemusi koncit 0) Uz vim, ze je to v principu spatne a prvni cast si
>>>>>>> sahne mimo rozsah pole, ale ze by to prekladac poresil takto?
>>>>>>>
>>>>>>> Kdyz podminky prehodim
>>>>>>>
>>>>>>> for (int idx=0; idx < sizeof(rec.recTxt.text) &&
>>>>>>> rec.recTxt.text[idx] != 0; idx++)
>>>>>>>
>>>>>>> Tak to funguje OK ale uz jsem nemel cas zkoumat disassembler. V
>>>>>>> neoptimalizovanem kodu to fungovalo i pro prvni variantu.
>>>>>>>
>>>>>>> Vysvetli to chovani nekdo?
>>>>>>>
>>>
>>> _______________________________________________
>>> 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