(++i)*(++i)

Oto Buchta oto_b na jezek.buchtovi.cz
Pondělí Únor 1 09:56:41 CET 1999


Dne Pá, 29 leden 1999 Jan Kurik napsal(a):
>> myslite si, ze je v C mozno pouzit (s jednoznacne definovanym
>>vysledkem) konstrukci ze Subjectu - (++i)*(++i)? Pri zkompilovani
>>gcc 2.7.2.3 i egcs-1.03 je vysledek druha mocnina, coz neni to, co bych
>>si predstavoval. Pritom po nahrazeni ++i za i+=1, coz by melo byt
>>ekvivalentni, je vysledek v poradku - pro nejake puvodni i to vrati
>>(i+1)*(i+2).
>
>
>                                                    
>        printf("(i++)*(i++) = %i\n", (i++)*(i++));  
>        i = 10;                                     
>        printf("(i+1)*(i+1) = %i\n", (i+1)*(i+1));  
>        printf("(i+1)*(i+2) = %i\n", (i+1)*(i+2));  
>        printf("(i+2)*(i+2) = %i\n", (i+2)*(i+2));  
>        printf("(++i)*(++i) = %i\n", (++i)*(++i));  
>};
>< C code END>
>
>no a vysledky :
>
>(i++)*(i++) = 100
>(i+1)*(i+1) = 121
>(i+1)*(i+2) = 132
>(i+2)*(i+2) = 144
>(++i)*(++i) = 144
>
>takze konstrukce >>(++i)*(++i)<< udela totez co >>(i+2)*(i+2)<<, coz je
>podle mne vzhledem k priorite zavorek OK. Zkusil jsem to i na "MS VisualC++
>5.0" a vysledky byly stejne. > >
Podle mne je zásadní chyba v optimalizaci.
Pravděpodobně někde mezi lexikálním a syntaktickým analyzátorem dojde ke
spojení kódu a (++i)*(++i) je nahrazeno LEX1*LEX2, porovnány LEX1 a LEX2 a
provedeno #define LEX3=LEX2 a celý výraz nahrazen LEX3*LEX3.
Do tabulky je uložen LEX3 a při předpočítání výsledku dojde k tomu, že je
vygenerováno mov LEX3,ADDR(i); inc(LEX3); inc(LEX3); result=LEX3^2;
Tady bych viděl chybu kompilatoru, nikoli programátora.

Dalším řešením je, že se předávají pouze pointery na výsledky nebo
proměnné. A protože ++i je operace, která se provede před předáním pointeru,
ve výsledku se vezme proměnná i, provede akce ++i, předá se zpět pointer na i, 
vezme se proměnná i, provede akce ++i, předá se zpět pointer na i a úplně
nakonec se vezmou oba pointery, vynásobí se hodnoty, na které ukazují a
výsledek je výsledek. Opět chybný výklad akce. Já přeci chci, aby se mi
výsledky mezivýpočtů ukládaly pro následný výpočet. Pak by ale bylo
jasné, proč správně funguje i+=1. Pro výpočet výrazu se využívá výsledek,
který evidentně nemůže být uložen v proměnné, a musí se tudíž hodit asi
na haldu nebo kam.
Opravdu začínám mít dojem, že optimalizace kódu, jak je udělaná v gcc 2.7, je
fakt zajímavá.

Telcontar


Další informace o konferenci Linux