W każdym z poniższych przypadków “cout<<…” Dev zwraca mi 1. Czy jest jakaś zasada kolejności wartościowania argumentów? Czy rezultaty są jednoznaczne (nie zależą od implementacji?)?
++t/++t => 11/12=>daje 1(mimo że jest to 0,… dlaczego zaokrągla w górę?)
++t/–t => 11/10 => 1 (ok)
–t/++t => 9/10 => daje znów 1
–t/–t => 9/8 => daje 1 (ok)
#include
using namespace std;
int main(int argc, char *argv[])
{int t=10;
cout<<++t/++t; //++t/--t //--t/++t /--t/--t <= cztery przypadki
system("PAUSE");
return EXIT_SUCCESS;
}
Ale gdy wykonałem działanie 5/6 (przy int) dało wynik 0 (poprawny). Więc proszę o wyjaśnienie, dlaczego otrzymałem takie wyniki?
Rozumiem, więc jeśli takie cos zobaczę, to powinienem napisać komentarz - wynik niejednoznaczny? Albo jeśli będą ode mnie chceli wyniku (Dev liczy wszystko), to mam wpisać 1??
Najpierw daje poprawne wyniki (choć nadal wyrzuca ostrzeżenie, że wynik może być niezdefiniowany). W drugim przypadku są u mnie same 1, co pokazuje, że faktycznie wyrażenie w stylu ++t/++t jest niezdefiniowane, bo teoretycznie kod robi to samo, a wyniki różne. Wygląda to tak, np. dla t = 10 dla ++t/++t najpierw oblicza lewy operand (t == 11) i zamiast robić kopię zmiennej po prostu kompilator wie, że jej wartość będzie w zmiennej t, następnie oblicza prawy operand (t == 12) i analogicznie jak poprzednio, po co robić kopię, skoro wartość wyrażenia jest w zmiennej t? Następnie bierze wartości t, t/t == 1, najpewniej jest tak jak to opisałem
Dobra wszystko ok, ale powiedz mi jedno. Dlaczego jak dzielę przez siebie liczby calkowite w tych podpunktach B wychodzą same 1, mimo że dzielę np 9/10? dlaczego zaokrągla w górę? Bo w podpunktach A dzielenie liczb calkowitych daje poprawne wyniki tzn. tam gdzie ma być 0 jest 0, a tam gdzie ma być 1 jest 1.
#include
using namespace std;
struct smth {
int operator()(int i) { std::cout << ++c << ": " << i << std::endl; return i; }
static int c;
};
int smth::c = 0;
int main()
{
smth t;
int a = 10;
cout << "A1: " << t(++a) / t(++a) << endl;//0
a = 10;
cout << "A2: " << t(--a) / t(++a) << endl;//0
a = 10;
cout << "A3: " << t(++a) / t(--a) << endl;//1
a = 10;
cout << "A4: " << t(--a) / t(--a) << endl;//1
int b = 10;
cout << "B1: " << ++b / ++b << endl;//1
b = 10;
cout << "B2: " << --b / ++b << endl;//1
b = 10;
cout << "B3: " << ++b / --b << endl;//1
b = 10;
cout << "B4: " << --b / --b << endl;//1
system("PAUSE");
return EXIT_SUCCESS;
}
Przecież właśnie to napisałem. Najpewniej jest tak, że wartości wyrażeń są obliczane (czyli t zwiększa się o dwa), ale nie jest robiona kopia wartości wyrażenia ++t, po prostu ‘t’ jest zwiększane dwukrotnie i później bezpośrednio program odwołuje się do wartości t, więc w rzeczywistości jest to tyle co t/t, czyli (prawie) zawsze 1. Jest to więc kolejno 12/12, 10/10, 10/10, 8/8.
Ok, ale z --b/++b to nie rozumiem. jeżeli jest tak jak piszesz, to mamy: (10-1)/(10+1), czyli w double 0.9, a w int daje 1 (domyślne zaokrąglanie w górę?).
Sęk w tym, że wartości wyrażeń ++t lub --t nie są kopiowane
Zobacz:
#include
int divide(int a, int b)
{
std::cout << "args (" << a << ", " << b << ")\n";
return a / b;
}
int main()
{
int t = 10;
std::cout << divide(++t, ++t) << std::endl;
t = 10;
std::cout << divide(--t, ++t) << std::endl;
return 0;
}
Najpierw obliczane są operandy (co oczywiste), ale wartości tych wyrażeń nie są kopiowane, funkcja/operator cały czas odwołują się do tego samego miejsca w pamięci, do zmiennej ‘t’. Co byś nie zrobił na ‘t’ i tak ostatecznie będzie to wyrażenie t/t.