zakerna zahada GCC

Jaroslav Buchta jaroslav.buchta na hascomp.cz
Středa Únor 7 21:32:52 CET 2018


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



Další informace o konferenci Hw-list