[ leka @ 11.12.2003. 10:17 ] @
Ovaj primer je preuzet sa odlicnog http://www.programiranje.net foruma i odlican je kada treba na konkretnom primeru prikazati razlike medju kompajlerima.

Kod:
Code:

#include <iostream> 
#include <cstdlib> 
using namespace std; 

int main()

   int arr[2] = {1, 1}; 
   int a = 0; 
   a = arr[a]++; 
   cout << "a: " << a << endl; 
   cout << "arr[0]: " << arr[0] << endl; 
   cout << "arr[1]: " << arr[1] << endl; 
   system("pause"); 
   return 0; 
}


MinGW:
Code:

a: 1
arr[0]: 2
arr[1]: 1
Press any key to continue . . .


Microsoft Visual C++ 6.0
Code:

a: 1
arr[0]: 1
arr[1]: 2
Press any key to continue . . .

[ filmil @ 11.12.2003. 10:50 ] @
Rekao bih da se to pre zove „bag u VC++ 6.0“ nego „razlike između kompajlera“. Silno bih voleo da čujem objašnjenje zašto VC++6.0 pristupa a[1], a ne a[0].

f
[ leka @ 11.12.2003. 12:03 ] @
Pa i da je bug, opet je to razlika u kompajlerima, jel'te? :)
[ MilošV @ 11.12.2003. 12:37 ] @
Samo da dodam :)
Borland:
Code:
a: 1
arr[0]: 2
arr[1]: 1
Press any key to continue . . .
[ Ivan Dimkovic @ 11.12.2003. 12:38 ] @
Izgleda kao bag vc++ 6, Intel C++ daje:

a: 1
arr[0]: 2
arr[1]: 1


filmil: VC++ pristupa a[0], ali ga ne povecava (a = arr[a]++; ) vec prvo sa ++ poveca a, pa radi referenciranje arr[a] ?!?!

Debug:

Pre a = arr[a]++;

a 0
arr[a] 1


Posle:
a 1
arr[a] 2

Reklo bi se da VC++ prvo uveca brojac sa '++' pa onda referencira [a].. kako je po ISO C++ definisan redosled (i da li je) to mora da kaze neki C++ expert ovde :)
[ srki @ 11.12.2003. 13:04 ] @
Nije nikakav bag. To je verovatno posledica ukljucenih optimizacija (kod MinGw ili kod VC-a).

A zasto nije bag? Po standardu vrednost je nedefinisana.
To je slicno ovome: http://www.eskimo.com/~scs/C-faq/q3.1.html
U stvari slicnije je ovome:
http://www.eskimo.com/~scs/C-faq/q3.2.html

A i da je bag, zar ne bi ovo bio bag MinGW-a? Jer kada se uradi arr[a]++ a je 1 pa znaci da je VC ispravno uradio.
[ filmil @ 11.12.2003. 13:07 ] @
Izgleda da je krajnje vreme da se kupi standard za C++.

Kao što je opšte poznato, i = i++ je izraz koji se podvodi pod „nedefinisano ponašanje“ pa je svaki rezultat operacije prihvatljiv.

Ali, to koliko vidim nije isto kao i:

a = arg[a]++.

Što se tiče redosleda izvršavanja, [] ima veći prioritet nego ++, prema standardu.

Citat:

filmil: VC++ pristupa a[0], ali ga ne povecava (a = arr[a]++; ) vec prvo sa ++ poveca a, pa radi referenciranje arr[a] ?!?!


To bi bilo kršenje semantike jezika. ++ uvećava izraz koji je njegov argument. Koliko vidim, VC++ pri računanju izraza ispravno dodeli a = 1, ali zatim kada računa adresu izraza kog treba inkrementirati koristi novu vrednost a za indeksiranje. Koliko sam video u nezvaničnim člancima koji se mogu pronaći na Guglu, to _nije_ ono što bi trebalo da se dogodi. Jer naime:

a = b++;

treba da inkrementira promenljivu b, koja god ona bila. U gornjem izrazu se može videti da se b preslikava u arg[0] tako da bi trebalo da se inkrementira arg[0], bez obzira što je a promenilo vrednost u međuvremenu. Ali naravno, neformalni članci se komotno odnose prema ovim finesama, a C standarda bez plaćanja nema ni od korova — čak ni u biblioteci!

f
[ filmil @ 11.12.2003. 13:21 ] @
Citat:
srki:
Nije nikakav bag. To je verovatno posledica ukljucenih optimizacija (kod MinGw ili kod VC-a).

Ne bih rekao. Optimizacija je transformacija koda koja daje kod čiji je izlaz uvek ekvivalentan izlazu polaznog programa.

Ako se olabavi taj uslov, onda se svaki program može „izoptimizovati“ do 0 bajtova dužine.

A „agresivne optimizacije“ koje menjaju semantiku programa su marketinški eufemizam. Mnogo je lepše reći „naš kompajler toliko agresivno optimizuje kod da se može desiti da posle optimizacije ne bude ispravan“ nego „naš kompajler ima grešku u algoritmu za optimizaciju“.

Šta onda da pitaju mušterije? Da li optimizacija radi uvek, ponekad ili nikad?

Citat:

A zasto nije bag? Po standardu vrednost je nedefinisana.
To je slicno ovome: http://www.eskimo.com/~scs/C-faq/q3.1.html
U stvari slicnije je ovome:
http://www.eskimo.com/~scs/C-faq/q3.2.html

Na žalost nemam standard pored sebe pa pričam napamet ali ne bi se reklo da je primer sličan ijednom od tih. U oba primera iz C FAQ-a se govori o inkrementiranju promenljive koja se koristi za izračunavanje izraza, a ovde to nije slučaj. Ovde se inkrementira promenljiva koja nema veze sa a.

f
[ srki @ 11.12.2003. 13:34 ] @
Citat:
filmil:
Citat:
srki:
Nije nikakav bag. To je verovatno posledica ukljucenih optimizacija (kod MinGw ili kod VC-a).

Ne bih rekao. Optimizacija je transformacija koda koja daje kod čiji je izlaz uvek ekvivalentan izlazu polaznog programa.
Ma naravno. Nisam na to mi mislio. Ali ako je vrednost nedefinisana po standardu onda moze da se razlikuje optimizovana i neoptimizovana verzija. Zato sam rekao da je to mozda posledica optimizacije nekog od kompajlera.

Recimo ovaj kod za zamenu promenljive je po standardu nedefinisan i kada su ukljucene optimizacije moze svasta da bude:
Citat:
For example, it has been reported that when given the code
int a = 123, b = 7654;
a ^= b ^= a ^= b;
the SCO Optimizing C compiler (icc) sets b to 123 and a to 0.


Citat:
Šta onda da pitaju mušterije? Da li optimizacija radi uvek, ponekad ili nikad?
Ako postujes standard optimizacija ce uvek da radi ali ako ne postujes onda moze da se razlikuje rezultat.

Citat:

Na žalost nemam standard pored sebe pa pričam napamet ali ne bi se reklo da je primer sličan ijednom od tih.
Pa i ja sam na brzinu odgovorio. Ucinilo mi se da je prvi primer slican. Mada u stvari prvi primer i jeste slican jer tu isto zavisi da li ima prednost [] ili ++. Zar ne?

Citat:
U oba primera iz C FAQ-a se govori o inkrementiranju promenljive koja se koristi za izračunavanje izraza, a ovde to nije slučaj. Ovde se inkrementira promenljiva koja nema veze sa a.
Pa ima veze sa 'a' ali posrednu vezu.

Sad cu da pogledam da li pise nesto o tome u c++ standardu iz '98 jer sam ga skinuo pre neki dan sa nekog ruskog sajta.
[ leka @ 11.12.2003. 14:09 ] @
srki, ne znam sta pokusavas da dokazes...

Treba razumeti operatore ++ i --. Evo sta kaze dokumentacija za njih:



Increment operator ( ++ )

Syntax

postfix-expression ++ (postincrement)

++ unary-expression (preincrement)

The expression is called the operand. It must be of scalar type (arithmetic or pointer types) and must be a modifiable lvalue..

Postincrement operator

The value of the whole expression is the value of the postfix expression before the increment is applied.

After the postfix expression is evaluated, the operand is incremented by 1.

Preincrement operator

The operand is incremented by 1 before the expression is evaluated. The value of the whole expression is the incremented value of the operand.

The increment value is appropriate to the type of the operand.

Pointer types follow the rules for pointer arithmetic.

Decrement operator ( -- )

Syntax

postfix-expression -- (postdecrement)

-- unary-expression (predecrement)

The decrement operator follows the same rules as the increment operator, except that the operand is decremented by 1 after or before the whole expression is evaluated.


Ono sto ja pokusavam reci (ne i da dokazem :) je da prici o optimizaciji operatora ++ i -- ovde nema mesta...
[ leka @ 11.12.2003. 14:18 ] @
Danas nisam imao vremena i za BCC, tako da cu sada da ispravim stvar:
Code:

C:\prj\cxx>bcc32 test.cpp
Borland C++ 5.6.4 for Win32 Copyright (c) 1993, 2002 Borland
test.cpp:
Turbo Incremental Link 5.65 Copyright (c) 1997-2002 Borland

C:\prj\cxx>test.exe
a: 1
arr[0]: 2
arr[1]: 1
Press any key to continue . . .
[ leka @ 11.12.2003. 14:19 ] @
Tizo, izvini, nisam video tvoj tekst... :(
[ Ivan Dimkovic @ 11.12.2003. 14:33 ] @
Ovu glavolomku ce resiti neko ko ima kopiju ISO C++ standarda.... i ko ce nam reci da li je ovo definisano standardom ili ne...

Mada je malo cudno da samo MSVC ima probleme sa ovim a da svi ostali rade upravo suprotno.. zanimljivo.

Srki: problem se desava i sa debug i sa release verzijama, tako da ga ne bih pripisao optimizatoru vec samom kompajleru.
[ filmil @ 11.12.2003. 14:55 ] @
Citat:
srki:
Ako postujes standard optimizacija ce uvek da radi ali ako ne postujes onda moze da se razlikuje rezultat.

Tu je marketing malo više učinio svoje, ali neću komentarisati dalje, pošto je u ovoj temi OT. Daj da rešimo polazni problem. :)

Citat:

Pa i ja sam na brzinu odgovorio. Ucinilo mi se da je prvi primer slican. Mada u stvari prvi primer i jeste slican jer tu isto zavisi da li ima prednost [] ili ++. Zar ne?

Pre nego što sam odgovorio potražio sam standard u biblioteci. Prioriteti operatora su dobro definisani i uvek je [] većeg prioriteta nego ++. (http://www.difranco.net/cop2220/op-prec.htm)

Citat:
Sad cu da pogledam da li pise nesto o tome u c++ standardu ...


Očekujem(o) nestrpljivo.

f
[ Dragi Tata @ 11.12.2003. 16:22 ] @
Nemam ni ja standard, ali imam "Bibliju" (The C++ Programming Language 3rd edition - B. Stroustrup). Elem, najpre u odeljku 6.2 Operator summary strana 120 imate operatore poređane po prioritetu i tu se vidi da subscripting i post increment imaju isti prioritet. Onda liznete prst, okrenete stranu i vidite paragraf 6.2.2 Evaluation Order, strana 122:

Citat:
The order of evaluation of subexpressions within an expression is undefined. In particular, you cannot assume that the expression is evaluated left to right.


Dakle, standard dozvoljava i jedno i drugo. Međutim, ja sam gori od standarda i kad bih video takav kod u programu koji održavam, autor bi leteo kroz prozor...
[ Ivan Dimkovic @ 11.12.2003. 16:28 ] @
Citat:

Dakle, standard dozvoljava i jedno i drugo. Međutim, ja sam gori od standarda i kad bih video takav kod u programu koji održavam, autor bi leteo kroz prozor...


Ja sam hteo isto da kazem.. no reko', prvo da proverimo kako stoji to sa standardom pre nego sto ospem paljbu :-) Ko pise ovakav kod zasluzuje da umre :)

Nije mi jasno sta se postize sa ovom kripticnoscu osim mogucnosti da to negde ne proradi ...
[ filmil @ 11.12.2003. 16:32 ] @
Citat:
Dragi Tata:
poređane po prioritetu i tu se vidi da subscripting i post increment imaju isti prioritet.

Ovaj... a šta je onda sa referencama u kojima stoji da [] ima veći prioritet od .++? Jedan od linkova sam već dao, a ima ih dosta.

f
[ Dragi Tata @ 11.12.2003. 16:45 ] @
Filipe, ja gledam Stroustupovu knjigu. Ako laže on, lažem i ja.

Što se linkova tiče, ovaj koji si ti ostavio
http://www.difranco.net/cop2220/op-prec.htm

uopšte ne pominje postinkremetiranje, već samo preinkrement

ovaj:

http://www.cppreference.com/operator_precedence.html

grupiše oba operatora u isti koš, ali ni tu se ne pravi razlika između pre i post inkrementacije, što je greška.

ovaj:
http://www.cs.niu.edu/~abyrnes/csci241/precedence.htm

kaže nešto slično kao što ti tvrdiš, ali bih rekao da greše, a još su i nepotpuni.

ovaj:

http://web.ics.purdue.edu/~cs240/misc/operators.html

opet ne pravi razliku između pre i post inkrementiranja

itd, itd...
[ Dragi Tata @ 11.12.2003. 16:52 ] @
E, da. Tabela u BS knjizi je slična ovoj na MSDN-u, samo što je potpunija:

http://msdn.microsoft.com/libr...pluslang_c.2b2b_.operators.asp

Mada, zanimljivo je da su se i u MS dokumentaciji zeznuli:

Citat:
Operators in the same segment of the table have equal precedence and are evaluated left to right in an expression unless explicitly forced by parentheses.


Kao što smo videli, ovo nije tačno, ali po standardu i ne mora da bude tačno.
[ Ivan Dimkovic @ 11.12.2003. 17:01 ] @
http://anubis.dkuug.dk/jtc1/sc22/open/n2356/

Ovo je CD (commitee draft) dakle vrlo rana faza standarda, ali pretpostavljam da nista nije menjano do IS faze, tako da je valjda OK da se koristi kao referenca:

5. Expressions:

4 Except where noted, the order of evaluation of operands of individual
operators and subexpressions of individual expressions, and the order
in which side effects take place, is unspecified. Between the previ-
ous and next sequence point a scalar object shall have its stored
value modified at most once by the evaluation of an expression. Fur-
thermore, the prior value shall be accessed only to determine the
value to be stored. The requirements of this paragraph shall be met
for each allowable ordering of the subexpressions of a full expres-
sion; otherwise the behavior is undefined.

[Example:
i = v[i++]; // the behavior is undefined
i = 7, i++, i++; // `i' becomes 9

i = ++i + 1; // the behavior is undefined
i = i + 1; // the value of 'i' is incremented
--end example]

[ markom @ 11.12.2003. 21:06 ] @
Evo sedimo Alex i ja ovde jedan pored drugog i lomimo glavu oko ovoga.

Ovde neko nekoga u zdrav mozak, ako mene pitate.

Izraz:

Code:

a = arr[a]++;


bi po svoj zdravoj logici morao da bude ekvivalentan:
Code:

b = a;
a = arr[a];
arr[b] = arr[b]+1;


Sve drugo je, po mom mišljenju bug u kompajleru. U linku koji je drug Dimković ;-) poslao, data situacija NIJE deklarisana kao nedefinisana.

Šta VC kaže kad mu se podmetne ovaj kod?

Code:

int main()

   int arr[2] = {1, 1}; 
   int a = 0; 
   a = arr[a]++; 
   printf("a: %d\n", a);
   printf("arr[0]: %d\n", arr[0]);
   printf("arr[1]: %d\n", arr[1]);
   return 0; 
}


koji se kompajlira kao čist C?


M&A.
[ Dragi Tata @ 11.12.2003. 21:46 ] @
Citat:
mdm:
Izraz:

Code:

a = arr[a]++;


bi po svoj zdravoj logici morao da bude ekvivalentan:
Code:

b = a;
a = arr[a];
arr[b] = arr[b]+1;


Sve drugo je, po mom mišljenju bug u kompajleru.


Drugovi Islanđani su u pravu sa stanovišta "zdrave logike", ali ovde ne raspravljamo šta je logično, već šta je u skladu sa C++ standardom. Koliko sam ja u stanju da vidim, VC++ postupa u skladu sa standardom jer:

1) subscript operator i postinkrement imaju podjednak prioritet
2) Redosled evaluacije podizraza unutar izraza nije definisan

Mada je to potpuno nebitno, jer bi jedino lud čovek mogao da napiše tako nešto, osim iz zezanja.
[ srki @ 11.12.2003. 23:25 ] @
Citat:
filmil:
Ovaj... a šta je onda sa referencama u kojima stoji da [] ima veći prioritet od .++? Jedan od linkova sam već dao, a ima ih dosta.

Filipe, to je tacno zbog toga sto obicne zagrade imaju prednost. arr[a]++ se prevodi kao *((arr)+(a)) pa se to u zagradama racuna pre ++ sto je i logicno. Ali tu postoji problem jer je a na dva mesta referencirano pa mislim da je zbog toga nedefinisano. (Jednom je korisceno kod dodele a jednom kod ++)

Jer ako bi
Code:
a=b++

trebalo da se prevodi u ovo:
Code:

a=b;
b++


zar ne bi trebalo onda
Code:

a=arr[a]++

da se prevodi u ovo
Code:

a=arr[a];
arr[a]++;


ako bi bilo tako onda bi znacilo da MinGW gresi mada ovde verovatno nijedan kompajler ne gresi ako je vrednost nedefinisana.
Tako ni izraz i=7; izraz=(i++)*(i++); nije definisan jer neki kompajler ce da da 49 a neki 56. Znaci to je isto kao razlika izmedju ovog gore i onoga sto je marko dao. Da li ce da se pamti ono sto se menja prilikom sledeceg koriscenja ili nece.

Imate ovde standard:
http://it-books.narod.ru
a imate i The C++ Programming Language, Third Special Edition
od Bjarne Stroustrup
[ filmil @ 12.12.2003. 00:50 ] @
Iz ove diskusije izvukao sam dve pouke:

- Ako se u C ili C++ programima pojavi izraz između dva „sequence pointa“ koji sadrži sporedne efekte, i ako redosled izvršavanja sporednih efekata i operacija nije jednoznačan, onda je izraz bar nedefinisan, a možda i nelegalan.

Ako je izraz nedefinisan, bilo koji rezultat izvršenja operacije je moguć, čak recimo i to da vam u trenutku izvršenja programa na vrata pozvoni Pamela Anderson. I svaka rasprava da u tom slučaju jedan kompajler prevodi ovako, a drugi onako je besmislena zato što programi treba da sadrže samo iskaze čija je semantika jednoznačna.

- Ne verujte svemu što pročitate na internetu, a dodao bih pogotovo ako su u pitanju diskusije na popularne teme kao što je C. Svi redom kače svoje „tutorijale“ koji su ovakvi ili onakvi, ali u principu ne moraju da budu tačni.

f
[ Ivan Dimkovic @ 12.12.2003. 09:12 ] @
Citat:

- Ako se u C ili C++ programima pojavi izraz između dva „sequence pointa“ koji sadrži sporedne efekte, i ako redosled izvršavanja sporednih efekata i operacija nije jednoznačan, onda je izraz bar nedefinisan, a možda i nelegalan.


Ovaj koji smo naveli nije legalan - jer se u C++ standardu (bar u onom draftu) pominje:

Citat:

Between the previ-ous and next sequence point a scalar object shall have its stored value modified at most once by the evaluation of an expression.


Mislim da bi C++ kompajler trebao da izbaci warning koji bi autora upozorio da radi nesto sto nije definisano standardom i da moze dobiti neocekivan rezultat.
[ filmil @ 12.12.2003. 09:24 ] @
Citat:
Ivan Dimkovic:
Mislim da bi C++ kompajler trebao da izbaci warning koji bi autora upozorio da radi nesto sto nije definisano standardom

Očekivati tako pametno upozorenje od kompajlera čija je najčešća poruka o grešci „parse error“ je baš puno. :)
[ srki @ 22.12.2003. 17:17 ] @
Da malo osvezim temu.
Citat:
Dragi Tata:
Nemam ni ja standard, ali imam "Bibliju" (The C++ Programming Language 3rd edition - B. Stroustrup). Elem, najpre u odeljku 6.2 Operator summary strana 120 imate operatore poređane po prioritetu i tu se vidi da subscripting i post increment imaju isti prioritet
Ali ovde to ne vazi jer ono u zagradama mora prvo da se izracuna. To sto si procitao se odnosi na ovaj izraz:
expression++[expression2]
E tu se ne zna da li ce da se izracuna prvo expression ili expression2 sto je i logicno jer se to pretvara u *((expression++)+(expression2)).
Makar ja tako shvatam to sto si naveo ali mozda gresim.

Citat:
The order of evaluation of subexpressions within an expression is undefined. In particular, you cannot assume that the expression is evaluated left to right.


U standardu pise drugacije i pise unspecified umesto undefined sto znaci da Microsoft moze da stavi da se izracunava sleva na desno i da tako posmatras kada radis sa njihovim kompajlerom tako da nisu pogresili u dokumentaciji.
Mozes da skines standard sa onog sajta koji sam naveo.
Ovde je samo u pitanju side effect i to da li se operand dvaput izracunava kod nesto=operand++. Nisam uspeo da nadjem nesto o tome u standardu.
[ Dragi Tata @ 23.12.2003. 20:27 ] @
Citat:
srki:
Da malo osvezim temu.
Citat:
Dragi Tata:
Nemam ni ja standard, ali imam "Bibliju" (The C++ Programming Language 3rd edition - B. Stroustrup). Elem, najpre u odeljku 6.2 Operator summary strana 120 imate operatore poređane po prioritetu i tu se vidi da subscripting i post increment imaju isti prioritet
Ali ovde to ne vazi jer ono u zagradama mora prvo da se izracuna.


O kakvim zagradama govoriš?

a = arr[a]++;
[ srki @ 24.12.2003. 00:08 ] @
Citat:
Dragi Tata:
O kakvim zagradama govoriš?

a = arr[a]++;

Pa tu mora prvo da se izracuna *(arr+a) u svakom slucaju. Zbog toga kazem da mislim da se ono sto si procitao odnosi na ovo E1++[E2] i tu ne mozes da znas da li ce prvo da se racuna E1 ili E2 i zato je bitno da izracunavanje E1 ne utice na E2 i obrnuto (nema veze sa ovim primerom).

U ovom primeru je bitno da li se operand dvaput izracunava. Jednom prilikom kod rezlutata ++ a drugom prilikom kod povecavanja vrednosti. Ja nisam uspeo da nadjem. Nasao sam recimo za razliku izmedju E1=E1+1 i E1+=1.
U prvom slucaju se E1 dvaput izracunava a u drugom slucaju samo jednom.

P.S. DT, je l' nisi imao problema zbog zemljotresa?