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