Panel użytkownika
Nazwa użytkownika:
Hasło:
Nie masz jeszcze konta?

inkrementacja a cout

Ostatnio zmodyfikowano 2015-10-21 12:06
Autor Wiadomość
licsiu
Temat założony przez niniejszego użytkownika
inkrementacja a cout
» 2015-10-19 13:38:01
Witam wszystkich - pierwszy raz : )
zastanawia mnie mechanizm wypisywania na ekran inkrementowanych wartości int'a:

przykład:

int y;

y=0;
cout << y << y << endl;  // 00

y=0;
cout << ++y << y << endl;  // 10

// dotąd było wszystko jasne... od teraz już nie wiem czemu wypusuje to co w kom:

y=0;
cout << y++ << y << endl;  // 01   (dlaczego nie 00, ew 10?)

y=0;
cout << y << ++y << endl;   // 11

y=0;
cout << y << y++ << endl;   //10  (a to juz przekracza zupełnie moje wyobrażenie..)

pozdrawiam
będę wdzięczny za zainteresowanie.
Piotrek
P-138872
michal11
» 2015-10-19 14:42:16
Operator << to nic innego jak funkcja, to samo jest z operatorem ++. Czyli jedna z twoich linijek wygląda tak:
operator <<( operator <<( cout, y ), operator ++( y ) );

i w takim wypadku mógłbyś sobie pomyśleć, ze najpierw powinna wykonać się "lewa" funkcja a później prawa, prawda ? Niestety tak nie jest, standard nie definiuje w jakiej kolejności są wykonywane funkcje przekazywane jako argumenty funkcji.
W podanym przykładzie może najpierw wykonać się
operator ++( y )
 a dopiero później
operator <<( cout, y )
 a równie dobrze na innym kompilatorze może być odwrotnie.

Mam tylko nadzieje, że nic nie pokręciłem i pekfos mnie nie wyśmieje ;).
P-138875
Rashmistrz
» 2015-10-20 23:38:16
@licsiu
będę wdzięczny za zainteresowanie.
Zwykle robię co w mojej mocy. :-_/

@michal11
Z tego co ja wiem to wyrażenie jest brane od lewej do prawej:
Brany jest strumień (cout) i to co ma zostać wysłane do niego.
Wykonywana jest operacja wstawienia do strumienia (skrócone o inne),
a następnie jest zwracana referencja do otrzymanego strumienia.
Następnie przechodzi do wykonania kolejnego "<<"
i dzieje się tak, aż napotkany będzie średnik;

Tak dla mnie wygląda działanie tego kodu...
Dlatego nie potrafię się doszukać przyczyny takich wyników.

Ach ten lukier składniowy...
____________________________________

C/C++
#include <iostream>
using std::cout;
using std::endl;

int main()
{
    char tab1[] = { '0', '\0' };
    char & y = * tab1;
    cout <<( y++, tab1 ) << tab1 << endl; // 11
    y = '0';
    cout << tab1 <<( ++y, tab1 ) << endl; // 11 WTF ?
    y = '0';
    cout << tab1 <<( y++, tab1 ) << endl; // 11 (Jakim cudem?)
   
    char z = 'A';
    z = 'A';
    cout << z++ << z << endl; // AA
    z = 'A';
    cout << z << ++z << endl; // BB
    z = 'A';
    cout << z << z++ << endl; // BA
   
    cout << '\n';
   
    // ____________ OBRONA NAWIASAMI
   
    char tab2[] = { '0', '\0' };
    char & a = * tab2;
    ((( cout <<( a++, tab2 ) ) << tab2 ) << endl ); // 11 dobrze
    a = '0';
    ((( cout << tab2 ) <<( ++a, tab2 ) ) << endl ); // 11 dlaczego nie 01?
    a = '0';
    ((( cout << tab2 ) <<( a++, tab2 ) ) << endl ); // 11 dlaczego nie 01?
   
    char b = 'A';
    b = 'A';
    ((( cout << b++ ) << b ) << endl ); // AA ?
    b = 'A';
    ((( cout << b ) << ++b ) << endl ); // BB ?
    b = 'A';
    ((( cout << b ) << b++ ) << endl ); // BA ?
   
    cout << '\n';
   
    // ____________ AS z rekawa
   
    char c = '0';
    c = '0';
    cout.put( c++ ).put( c ).put( '\n' ); // 00 dlaczego nie 01?
    c = '0';
    cout.put( c ).put( ++c ).put( '\n' ); // 11 dlaczego nie 01?
    c = '0';
    cout.put( c ).put( c++ ).put( '\n' ); // 10 dlaczego nie 00?
   
    cout << '\n';
}

Mam tego dość. Nie rozumiem tego.
To całkowicie przechodzi moje pojęcie...

Próbowałem doszukiwać się problemu w
kolejności przy przeciążanych operatów... nic.
tego co powiedział kolega wyżej... nic.
czy undefined behavior'ach... nic.

Problem leży gdzieś głębiej czy indziej.
P-138972
Monika90
» 2015-10-21 12:06:50
Kolejność wartościowania podwyrażeń jest nieokreślona (poza pewnymi wyjątkami: || && ?: ,). Więc jeżeli masz kod taki jak ten
C/C++
cout << f() << g() << h() << endl;
to nie wiesz w jakiej kolejności wywołane zostaną funkcje f, g i h. Kompilator może wybrać jedną z 6 możliwości, co więcej, nie musi to być za każdym razem ta sama kolejność.

Jeżeli te podwyrażenia to nie są wywołania funkcji (np. użycie wartości lub modyfikacja zmiennej typu int), to jest jeszcze gorzej, bo w ogóle nie ma żadnej kolejności. A gdy nie ma kolejności między takimi operacjami, jak zapis i odczyt tej samej zmiennej (typu skalarnego), albo dwa zapisy do tej samej zmiennej (typu skalarnego), to zachowanie programu jest niezdefiniowane.

P-138976
« 1 »
  Strona 1 z 1