operator inkrementacji w C# i C++

operator inkrementacji w C# i C++
ZK
  • Rejestracja:prawie 7 lat
  • Ostatnio:5 miesięcy
  • Postów:273
0

Ten sam program daje w zależności od języka wynik 39 w C++ 36 w C#.
Który waszym zdaniem sposób liczenia jest lepszy ? Z czego to wynika ?

Kopiuj
using System;

namespace ConsoleApp16
{
    class Program
    {
        static void Main(string[] args)
        {
            int a = 10;
            int wynik = ++a + ++a + ++a;
            Console.WriteLine(wynik);
        }
    }
}
Kopiuj
#include "pch.h"

using namespace System;

int main(array<System::String ^> ^args)
{
    
    int a = 10;
    int wynik = ++a + ++a + ++a;
    Console::WriteLine(wynik);

}
stivens
  • Rejestracja:ponad 8 lat
  • Ostatnio:około 3 godziny
0

Po co w ogole tak pisac


λλλ
Zobacz pozostałe 27 komentarzy
enedil
@alagner: to była dygresja. Ja volatile używałem właśnie tylko na mikrokontrolerach. Tutaj z kolei to Ty się kłócisz nie wiadomo po co, jak ja nawet nie mam odmiennego zdania od Twojego
AL
@enedil: nie, nie; nie kłócę się, wybacz jeśli to tak odebrałeś, zasadniczo się zgadzamy tutaj. Jedyne co mi w Twojej wypowiedzi nie do końca pasuje to "volatile jako metoda zapobiegania UB", ale zakładam, że to skrót myślowy ;)
ZK
OK ," Już każdy powiedział to co wiedział Trzy razy wysłuchał dobrze mnie Wszyscy zgadzają się ze sobą A będzie nadal tak jak jest" Koniec tematu
enedil
@Zimny Krawiec: jak chcesz wiedzieć czemu masz 39 to spójrz w disassembler. Nie jest to w żaden sposób kwestia języka programowania. Ponadto, jestem w stanie uwierzyć, że w zależności od miejsca pojawienia się i reszty kodu, możesz dostać zgoła różne wyrażenia.
ZK
Z chęcią to zobaczę .
PL
  • Rejestracja:około 7 lat
  • Ostatnio:ponad 2 lata
  • Postów:104
0

Ale to nie jest prawdziwy C++ tylko C++.NET

ZK
to nie ma znaczenia . Akurat tak jest chyba w każdym bo sprawdzałem
AN
  • Rejestracja:prawie 19 lat
  • Ostatnio:około 3 godziny
1

Moim zdaniem, powinno być 36, bo w tym kawałku kodu a ma wartość 10, a potem następuje trzykrotna inkrementacja z podstawieniem, czyli int wynik = ++a + ++a + ++a; powinno być zamienione na int wynik = 11 + 12 + 13;.

Bardzo możliwe, że nie ma przyjętego jednoznacznego sposobu interpretacji tego zapisu i jest to zachowanie niezdefiniowane.

Jeszcze możliwa jest interpretacja dająca wynik 33 w ten sposób, że kompilator wyczuje, że int wynik = ++a + ++a + ++a; to jest to samo, co int wynik = t + t + t;, a t = ++a;, więc po podstawieniu wyjdzie int wynik = 11 + 11 + 11;.

edytowany 1x, ostatnio: andrzejlisek
ZK
tutaj chodzi o to że w C++ najpierw jest robiona 3 razy inkrementacja a potem jest aktualizowana wartość w każdym operandzie
enedil
To ostatnie to by był imo bug kompilatora. Nieciężko zauważyć, że jednak ++a zmienia stan (a więc common subexpression elimination nie może być zastosowane).
AdamWox
W ten sposób da 33 int wynik = a++ + a++ + a++; w C#
PL
  • Rejestracja:około 7 lat
  • Ostatnio:ponad 2 lata
  • Postów:104
0

Należałoby zdezasemblować binarki i zobaczyć jak wygląda kod IL.

ZK
  • Rejestracja:prawie 7 lat
  • Ostatnio:5 miesięcy
  • Postów:273
0

Tutaj masz C++ i C#

Kopiuj
.method assembly static int32  main(string[] args) cil managed
{
  // Code size       29 (0x1d)
  .maxstack  2
  .locals ([0] int32 a,
           [1] int32 wynik)
  IL_0000:  ldc.i4.s   10
  IL_0002:  stloc.0
  IL_0003:  ldloc.0
  IL_0004:  ldc.i4.1
  IL_0005:  add
  IL_0006:  stloc.0   
  IL_0007:  ldloc.0
  IL_0008:  ldc.i4.1
  IL_0009:  add
  IL_000a:  stloc.0  
  IL_000b:  ldloc.0
  IL_000c:  ldc.i4.1
  IL_000d:  add
  IL_000e:  stloc.0 
  IL_000f:  ldloc.0
  IL_0010:  dup
  IL_0011:  add
  IL_0012:  ldloc.0
  IL_0013:  add  
  IL_0014:  stloc.1
  IL_0015:  ldloc.1
  IL_0016:  call       void [mscorlib]System.Console::WriteLine(int32)
  IL_001b:  ldc.i4.0
  IL_001c:  ret
} // end of method 'Global Functions'::main
Kopiuj
.method private hidebysig static void  Main(string[] args) cil managed
{
  .entrypoint
  // Code size       30 (0x1e)
  .maxstack  3
  .locals init ([0] int32 a,
           [1] int32 wynik)
  IL_0000:  nop
  IL_0001:  ldc.i4.s   10
  IL_0003:  stloc.0
  IL_0004:  ldloc.0
  IL_0005:  ldc.i4.1
  IL_0006:  add
  IL_0007:  dup
  IL_0008:  stloc.0
  IL_0009:  ldloc.0
  IL_000a:  ldc.i4.1
  IL_000b:  add
  IL_000c:  dup
  IL_000d:  stloc.0
  IL_000e:  add
  IL_000f:  ldloc.0
  IL_0010:  ldc.i4.1
  IL_0011:  add
  IL_0012:  dup
  IL_0013:  stloc.0
  IL_0014:  add
  IL_0015:  stloc.1
  IL_0016:  ldloc.1
  IL_0017:  call       void [mscorlib]System.Console::WriteLine(int32)
  IL_001c:  nop
  IL_001d:  ret
} // end of method Program::Main
edytowany 8x, ostatnio: Zimny Krawiec
Zobacz pozostałe 2 komentarze
ZK
Coś się skopało ale nie wiem jak to poprawić . ;)
AdamWox
trzy razy to apostrof -> enter -> kod -> enter -> trzy razy apostrof ;-)
Szalony Programista
Szalony Programista
Analizowaliście bytecode? 10 na stos, pop do a, a na stos, 1 na stos, add, 11 ze stosu do zmiennej a, zmienna a na stos, 1 na stos, add, 12 do zmiennej a, 12 na stos, 1 na stos, add, 13 do zmiennej a ze stosu, a na stos, duplicate stos, add, load a na stos, add, zapis do variable wynik, wynik na stos, call writelline. Dla drugiego kodu, 10 push, pop do var a, a na stos, 1 na stos, add dane na stosie, duplicate 11, 11, pop 11 do a, push 1, add, duplicate stos, pop do a, add wartosci na stosie, push a na stos, load 1 na stos, add, pop do wynik, push wynik, call writeline.
ZK
Jasne, że analizowałem. Kod jest taki jaki jest wynik. Dlaczego pytasz ?
Szalony Programista
Szalony Programista
Są drobne różnice między opcodami różnych procesorów i bytecodem różnych maszyn, ja np. nie analizowałem nigdy wcześniej bytecode od microsoftu, np. add dodaje 2 elementy ze stosu i usuwa je zastępując samym wynikiem na stosie, w procesorach* zwykle operacje dodawania wykonuje się na rejestrach itp.
lion137
  • Rejestracja:około 8 lat
  • Ostatnio:minuta
  • Postów:4888
0
Kopiuj
    int wynik = 0;
    int  a = 10;
    wynik = ++a + ++a + ++a;

C++, zgodnie z definicja "pre increment": Zanim wykonane jest przypisanie, zmienna jest inkrementowana o jeden; czyli, są dwa dodawania i trzy "pre inkrementacje" -
najpierw, ++a - a = 11 ;
teraz, inkrementujemy, a i dodajemy, 12 + 14, (pre inkrementacja);
finalnie, 11 + 12 + 14 = 37 - w g++ 9.3.0;
w jakim kompilatorze Ci wyszło 36?
A tak:

Kopiuj
    int wynik = 0;
    int  a = 10;
    wynik = ++a + (++a + ++a);

    cout << wynik <<"\n";   // -> 39

Najpierw:
11 + (12 + 13);
teraz, przed kolejnym przypisaniem, pre inkrementacja:
11 + ( 13 + 14)
i pre inkrementacja:
12 + (13 + 14) = 39
Czyli C#jakoś inaczej parsuje niż C++


somekind
Moderator
  • Rejestracja:około 17 lat
  • Ostatnio:około 3 godziny
  • Lokalizacja:Wrocław
1
lion137 napisał(a):

C++, zgodnie z definicja "pre increment": Zanim wykonane jest przypisanie, zmienna jest inkrementowana o jeden; czyli, są dwa dodawania i trzy "pre inkrementacje" -

Jest gdzieś taka definicja pre-increment w C++ publicznie dostępna i zaakceptowana jako jakiś standard? Bo bardzo wątpię...

W C# jest prosto - operator preinkrementacji zwraca zmieniony operand, więc wynik = ++a + ++a + ++a; oznacza: wynik = (10 + 1) + ((10 + 1) + 1) + (((10 + 1) + 1) + 1); (nawiasami otoczyłem oczywiście wyniki poprzednich inkrementacji.

W C++ zapewne definicji nie ma, więc co sobie kompilator wylosuje, to będzie. W tym przypadku najwyraźniej są robione najpierw 3 inkrementacje, a potem po prostu dodawane są trzy te same liczby. Wat.

najpierw, ++a - a = 11 ;
teraz, inkrementujemy, a i dodajemy, 12 + 14, (pre inkrementacja);
finalnie, 11 + 12 + 14 = 37 - w g++ 9.3.0;

No to to ma jeszcze mniej sensu niż 39. Ale znowu - to w końcu C++, więc implementation specific undefinded behaviour is the king.

AF
  • Rejestracja:prawie 18 lat
  • Ostatnio:17 dni
1

W C++ taka operacja jest undefined behavior, więc nie ma o czym dyskutować.

ZK
  • Rejestracja:prawie 7 lat
  • Ostatnio:5 miesięcy
  • Postów:273
0

@somekind: 39 ma według mnie największy sens bo to odpowiada takim instrukcjom :
++a;
++a;
++a;
wynik = a + a + a;
Nie każdy dostrzega że mamy jedną zmienną
Sprawdzałem na kilku kompilatorach i zawsze wychodzi 39.
Natomiast w C# jest tak :
wynik = (a + 1 ) + ( a + ( 1 + 1)) + (a + (1 + 1 + 1)); - tak jakbyśmy mieli kilka instancji tej samej zmiennej i każda ma inną wartość a w C++ zmienna a jest traktowana statycznie
Wniosek jest taki że lepiej nie zmieniać więcej niż 1 raz wartości tego samego operanda w jednym wyrażeniu bo każdy kompilator może liczyć inaczej.
To nie znaczy też jak inni sugerują że kompilator może policzyć cokolwiek jak funkcja Random . Po prostu nie wszystkie reguły są podawane w specyfikacjach

edytowany 4x, ostatnio: Zimny Krawiec
AL
  • Rejestracja:prawie 11 lat
  • Ostatnio:prawie 3 lata
  • Postów:1493
1

@Zimny Krawiec: najwyraźniej nie zawsze 39: https://godbolt.org/z/ax1jYe
O C# się nie wypowiem bo nie znam się na nim ponad rozumienie podstaw, ale w temacie C++ Twój post wprowadza w błąd.
To jest UB, tłumaczono Ci to wcześniej. Raz jeszcze: kompilator może zrobić cokolwiek (tu specyfikacja się kończy), typowo zachowa się tak, żeby wygenerować optymalny kod ale nie musi być to nijak przewidywalne powtarzalne i błędnie rozumujesz, że to nie jest podane w specyfikacji.

ZK
Nie zgodzę się z tym ale ci tego teraz ci tego nie udowodnię. Optymalizacja nie powoduje tego że otrzymamy inny wynik tylko np. że coś będzie działo szybciej albo nie będzie się niepotrzebnie powtarzać
AF
  • Rejestracja:prawie 18 lat
  • Ostatnio:17 dni
3
Zimny Krawiec napisał(a):

To nie znaczy też jak inni sugerują że kompilator może policzyć cokolwiek jak funkcja Random . Po prostu nie wszystkie reguły są podawane w specyfikacjach

Tu masz w standardzie języka podane, że to jest undefined behavior, czyli kompilator może iść i usunąć wszystko z dysku. Jak masz UB, to program jest niepoprawny. Jeżeli nie wiesz, co to jest UB, to nie zbliżaj się do C++, to nie jest "to nie jest zdefiniowane przez standard" tylko "to jest zdefiniowane przez standard jako zachowanie niezdefiniowane".

Zimny Krawiec napisał(a):

Nie zgodzę się z tym ale ci tego teraz ci tego nie udowodnię. Optymalizacja nie powoduje tego że otrzymamy inny wynik tylko np. że coś będzie działo szybciej albo nie będzie się niepotrzebnie powtarzać

Optymalizacja może zmienić wynik, może spowodować cofanie się w czasie albo inne nieogarnialne rzeczy. https://devblogs.microsoft.com/oldnewthing/20140627-00/?p=633

edytowany 1x, ostatnio: Afish
AL
  • Rejestracja:prawie 11 lat
  • Ostatnio:prawie 3 lata
  • Postów:1493
2

@Zimny Krawiec: nie udowodnisz bo nie masz racji:

[C++14: defns.undefined]: [..] Permissible undefined behavior ranges from ignoring the situation completely with unpredictable results, to behaving during translation or program execution in a documented manner characteristic of the environment (with or without the issuance of a diagnostic message), to terminating a translation or execution (with the issuance of a diagnostic message). [..]

https://www.nayuki.io/page/undefined-behavior-in-c-and-cplusplus-programs
To o czym mówisz to jest implementation defined i to jest coś innego. Ale nie ma zastosowania w tym przypadku.

edytowany 4x, ostatnio: somekind
AT
  • Rejestracja:ponad 9 lat
  • Ostatnio:23 dni
  • Postów:24
1

@Zimny Krawiec:
Wszelkie rozważania na temat tego, jak powinien działać program w przypadku w prowadzenia do niego undefined behavior nie mają sensu, ponieważ według specyfikacji C++ "[Undefined behavior] renders the entire program meaningless".
Dziękuje, do widzenia, zagadka rozwiązana, koniec tematu.

edytowany 1x, ostatnio: Aterwik
ZK
  • Rejestracja:prawie 7 lat
  • Ostatnio:5 miesięcy
  • Postów:273
0

@Aterwik: W innych językach jest inaczej niż w C++ ? Moim zdaniem jest tak samo .

Wibowit
  • Rejestracja:prawie 20 lat
  • Ostatnio:dzień
0
Zimny Krawiec napisał(a):

@Aterwik: W innych językach jest inaczej niż w C++ ? Moim zdaniem jest tak samo .

Obstawiam, że to raczej C++ jest niechlubnym wyjątkiem, a reszta popularnych języków ma wyspecyfikowane działanie pre- i post-inkrementacji.

Sprawdziłem działanie:

Kopiuj
var a = 0
wypisz(++a + ++a + ++a)

Na C#, Javie i JS i wszystkie wypisują 6. Nie chciało mi się sprawdzać tego twierdzenia o specyfikacji.

Ciekawostka. Co wypisze podany kod w C++:

Kopiuj
#include <iostream>

void printer(int a, int b, int c) {
  std::cout << a << " " << b << " " << c << std::endl;
}

int main() {
  int a = 0;
  printer(a++, a++, a++);
  return 0;
}

Odpowiedź:
Pod GCC wypisze: 2 1 0
Pod clangiem wypisze: 0 1 2 (i rzygnie ostrzeżeniem podczas kompilacji: warning: multiple unsequenced modifications to 'a' [-Wunsequenced])


"Programs must be written for people to read, and only incidentally for machines to execute." - Abelson & Sussman, SICP, preface to the first edition
"Ci, co najbardziej pragną planować życie społeczne, gdyby im na to pozwolić, staliby się w najwyższym stopniu niebezpieczni i nietolerancyjni wobec planów życiowych innych ludzi. Często, tchnącego dobrocią i oddanego jakiejś sprawie idealistę, dzieli od fanatyka tylko mały krok."
Demokracja jest fajna, dopóki wygrywa twoja ulubiona partia.
edytowany 1x, ostatnio: Wibowit
Azarien
w C# ++a zwiększa a i zwraca nową wartość. a++ również zwiększa a (natychmiast) i zwraca starą wartość. w ten sposób kombinowane wyrażenia z tymi operatorami mają zdefiniowany wynik.
ZK
  • Rejestracja:prawie 7 lat
  • Ostatnio:5 miesięcy
  • Postów:273
0

@Aterwik: Skoro tak wszystko wiesz to powiedz mi , czy na poziomie asemblera albo kodu maszynowego też możemy mieć niezdefiniowane zachowanie ?

Wibowit
  • Rejestracja:prawie 20 lat
  • Ostatnio:dzień
0
Zimny Krawiec napisał(a):

@Aterwik: Skoro tak wszystko wiesz to powiedz mi , czy na poziomie asemblera albo kodu maszynowego też możemy mieć niezdefiniowane zachowanie ?

Można mieć, np:
https://www.felixcloutier.com/x86/bsf
https://www.felixcloutier.com/x86/bsr

Poza tym masa instrukcji x86 pozostawia flagi procesora w stanie niezdefiniowanym.


"Programs must be written for people to read, and only incidentally for machines to execute." - Abelson & Sussman, SICP, preface to the first edition
"Ci, co najbardziej pragną planować życie społeczne, gdyby im na to pozwolić, staliby się w najwyższym stopniu niebezpieczni i nietolerancyjni wobec planów życiowych innych ludzi. Często, tchnącego dobrocią i oddanego jakiejś sprawie idealistę, dzieli od fanatyka tylko mały krok."
Demokracja jest fajna, dopóki wygrywa twoja ulubiona partia.
edytowany 1x, ostatnio: Wibowit
Azarien
  • Rejestracja:ponad 21 lat
  • Ostatnio:39 minut
0
Afish napisał(a):

Tu masz w standardzie języka podane, że to jest undefined behavior,

Co nie znaczy że to jest dobrze.
Uważam że to jest niedobrze, i takich UB nie powinno być w języku. W przytoczonym C# takie wyrażenia z ++ i -- mają zawsze zdefiniowany wynik o ile się kompilują (niektóre przypadki UB z C++ się w C# nie skompilują).
Kiedyś potrafiłem z głowy policzyć ile to będzie ++a + ++a + ++a w C#, teraz już mi się nie chce głowy zaśmiecać zbędnymi informacjami.

AF
  • Rejestracja:prawie 18 lat
  • Ostatnio:17 dni
0
Azarien napisał(a):

Co nie znaczy że to jest dobrze.
Uważam że to jest niedobrze, i takich UB nie powinno być w języku

Zgadzam się.

AL
no pełna zgoda tutaj też. Ale co z tego? @Afish chyba że planujesz lobbować w komitecie standaryzacyjnym?
AF
@Azarien napisał do mnie, to mu odpowiedziałem. Zwykła rozmowa.
AL
Po cichu liczyłem że odpowiesz "tak" ;)
G1
  • Rejestracja:około 4 lata
  • Ostatnio:4 dni
  • Postów:506
0

Kilka lat temu wyczytałem na tym forum właśnie w dziale c++, że ++n najpierw zmienia wartość zmiennej n a potem ją zwraca. Tak więc według mnie najrozsądniejszą analizą byłoby:

Kopiuj
int n=10;
Kopiuj
n = ++n + ++n
//++n: n = 11
//+
//++n: n = 12
//n = 23

Natomiast:

Kopiuj
n = n++ + n++
//n++: n = 10, po zwróceniu liczby 11
//+
//n++: n = 11, po zwróceniu liczby 12
//n = 21

Dobrze to rozumuję?

edytowany 1x, ostatnio: gswidwa1
stivens
To co napisales to belkot troche. Jezeli zaczynasz od n=10 to nie wazne czy zrobisz n++ czy ++n to i tak n bedzie wynosic w tym momencie 11 :)
ZK
z postinkrementacją jest jeszcze gorzej bo w samych implementacjach c++ są różnice
AF
@gswidwa1: Też bym tak to interpretował.
maszrum
  • Rejestracja:około 5 lat
  • Ostatnio:12 miesięcy
  • Lokalizacja:Kraków
  • Postów:219
0
Azarien napisał(a):
Afish napisał(a):

Tu masz w standardzie języka podane, że to jest undefined behavior,

Co nie znaczy że to jest dobrze.

A według mnie dobrze. Jak ktoś tworzy kwiatki w stylu int wynik = ++a + ++a + ++a;, to niech potem ma karę podczas debugowania. To tak trochę pół żartem, pół serio.

somekind
Moderator
  • Rejestracja:około 17 lat
  • Ostatnio:około 3 godziny
  • Lokalizacja:Wrocław
0
Zimny Krawiec napisał(a):

@somekind: 39 ma według mnie największy sens bo to odpowiada takim instrukcjom :

++a;
++a;
++a;
wynik = a + a + a;

Miałoby to sens, gdyby w specyfikacji było napisane, że najpierw wykonywane są wszystkie preinkrementacje, a potem wszystkie dodawania. Jeśli nie zostało to tak nigdzie zdefiniowane, to jest to wynik równie dobry jak każdy inny. Aczkolwiek dość nieintuicyjne byłoby zachowanie łamiące naturalną kolejność działań i precedens operatorów.

Natomiast w C# jest tak :
wynik = (a + 1 ) + ( a + ( 1 + 1)) + (a + (1 + 1 + 1)); - tak jakbyśmy mieli kilka instancji tej samej zmiennej i każda ma inną wartość

To wynika z opisanego w specyfikacji działania operatora preinkrementacji, który zwraca zmienną po zmianie oraz faktu, że dodawanie wykonywane jest od lewej do prawej, a więc najpierw zwiększamy, potem dodajemy znowu zwiększoną, a na końcu do sumy tych dwóch dodajemy zwiększoną trzeci raz.

Wniosek jest taki że lepiej nie zmieniać więcej niż 1 raz wartości tego samego operanda w jednym wyrażeniu bo każdy kompilator może liczyć inaczej.

W C++ tak. W językach, w których jest to precyzyjnie zdefiniowane problemu nie ma.

ZK
W każdym przypadku 3 inkrementacje są wykonywane przed dodawaniem tylko w C# każde wystąpienie zmiennej ma inną wartość
somekind
Nie, w C# jest: inkrementacja, inkementacja, dodawanie, inkrementacja, dodawanie. Według Twojego kompilatora C++ jest: inkrementacja, inkrementacja, inkrementacja, dodawanie, dodawanie.
G1
  • Rejestracja:około 4 lata
  • Ostatnio:4 dni
  • Postów:506
0

@stivens: A spróbuj np taki przykład:

Kopiuj
int[] tab = new int[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }
int n = 0;
Console.WriteLine(tab[n++]);
n = 0;
Console.WriteLine(tab[++n]);

Wynik:
0
1

Moje działania nie są bełkotem. Przy pierwszym Console.WriteLine zwróci Ci 0, ponieważ dopiero po zwróceniu aktualnej wartości zmienia ją o 1

edytowany 1x, ostatnio: gswidwa1
stivens
  • Rejestracja:ponad 8 lat
  • Ostatnio:około 3 godziny
0

n++ ma wartosc n ale po wykonaniu operacji zachodzi n = poczatkowa wartosc + 1
++n ma wartosc n+1 ale w obu przypadkach rejestr zawierajacy pamiec podpisana jako n ma dokladnie taka sama zawartosc.

A ty piszesz:

Kopiuj
int n=10;
//n++: n = 10, po zwróceniu liczby 11

No nie...


Zakladam ze myslisz moze i dobrze ale to co napisales to belkot.


λλλ
edytowany 3x, ostatnio: stivens
G1
  • Rejestracja:około 4 lata
  • Ostatnio:4 dni
  • Postów:506
0

"n++ ma wartosc n ale po wykonaniu operacji zachodzi n = początkowa wartosc + 1" - Tak właśnie to rozumuję, może źle to opisałem.

somekind
Moderator
  • Rejestracja:około 17 lat
  • Ostatnio:około 3 godziny
  • Lokalizacja:Wrocław
0
stivens napisał(a):

n++ ma wartosc n ale po wykonaniu operacji zachodzi n = poczatkowa wartosc + 1

++n ma wartosc n+1 ale w obu przypadkach rejestr zawierajacy pamiec podpisana jako n ma dokladnie taka sama zawartosc.

Rejestry to jedno, a drugie to to, co zwraca operator i co jest użyte jako składnik dodawania.

stivens
no dlatego mowie o wartosci wyrazenia i zawartosci rejestru
WeiXiao
  • Rejestracja:około 9 lat
  • Ostatnio:18 minut
  • Postów:5108
1

@Zimny Krawiec:

39 ma według mnie największy sens bo to odpowiada takim instrukcjom :
++a;
++a;
++a;
wynik = a + a + a;
Nie każdy dostrzega że mamy jedną zmienną
Sprawdzałem na kilku kompilatorach i zawsze wychodzi 39.
Natomiast w C# jest tak :
wynik = (a + 1 ) + ( a + ( 1 + 1)) + (a + (1 + 1 + 1)); - tak jakbyśmy mieli kilka instancji tej samej zmiennej i każda ma inną wartość a w C++ zmienna a jest traktowana statycznie
Wniosek jest taki że lepiej nie zmieniać więcej niż 1 raz wartości tego samego operanda w jednym wyrażeniu bo każdy kompilator może liczyć inaczej.
To nie znaczy też jak inni sugerują że kompilator może policzyć cokolwiek jak funkcja Random . Po prostu nie wszystkie reguły są podawane w specyfikacjach

nie wiem, jak się patrzy na drzewko to wynik 36 ma dużo sensu

\-CompilationUnitSyntax
|-UsingDirectiveSyntax
| \-IdentifierNameSyntax System
\-ClassDeclarationSyntax
\-MethodDeclarationSyntax
  |-PredefinedTypeSyntax
  |-ParameterListSyntax
  \-BlockSyntax
	|-LocalDeclarationStatementSyntax
	| \-VariableDeclarationSyntax
	|   |-PredefinedTypeSyntax
	|   \-VariableDeclaratorSyntax
	|     \-EqualsValueClauseSyntax
	|       \-LiteralExpressionSyntax
	|-LocalDeclarationStatementSyntax
	| \-VariableDeclarationSyntax
	|   |-PredefinedTypeSyntax
	|   \-VariableDeclaratorSyntax
	|     \-EqualsValueClauseSyntax
	_______________________________________________________
	|       \-BinaryExpressionSyntax
	|         |-BinaryExpressionSyntax
	|         | |-PrefixUnaryExpressionSyntax ++ 
	|         | | \-IdentifierNameSyntax a (makes 11)
	|         | \-PrefixUnaryExpressionSyntax ++ 
	|         |   \-IdentifierNameSyntax a (makes 12)
	|         \-PrefixUnaryExpressionSyntax ++
	|           \-IdentifierNameSyntax a (makes 13)
	_______________________________________________________
	\-ExpressionStatementSyntax
	  \-InvocationExpressionSyntax
		|-MemberAccessExpressionSyntax
		| |-IdentifierNameSyntax Console
		| \-IdentifierNameSyntax WriteLine
		\-ArgumentListSyntax
		  \-ArgumentSyntax
			\-IdentifierNameSyntax wynik
edytowany 2x, ostatnio: WeiXiao
Kliknij, aby dodać treść...

Pomoc 1.18.8

Typografia

Edytor obsługuje składnie Markdown, w której pojedynczy akcent *kursywa* oraz _kursywa_ to pochylenie. Z kolei podwójny akcent **pogrubienie** oraz __pogrubienie__ to pogrubienie. Dodanie znaczników ~~strike~~ to przekreślenie.

Możesz dodać formatowanie komendami , , oraz .

Ponieważ dekoracja podkreślenia jest przeznaczona na linki, markdown nie zawiera specjalnej składni dla podkreślenia. Dlatego by dodać podkreślenie, użyj <u>underline</u>.

Komendy formatujące reagują na skróty klawiszowe: Ctrl+B, Ctrl+I, Ctrl+U oraz Ctrl+S.

Linki

By dodać link w edytorze użyj komendy lub użyj składni [title](link). URL umieszczony w linku lub nawet URL umieszczony bezpośrednio w tekście będzie aktywny i klikalny.

Jeżeli chcesz, możesz samodzielnie dodać link: <a href="link">title</a>.

Wewnętrzne odnośniki

Możesz umieścić odnośnik do wewnętrznej podstrony, używając następującej składni: [[Delphi/Kompendium]] lub [[Delphi/Kompendium|kliknij, aby przejść do kompendium]]. Odnośniki mogą prowadzić do Forum 4programmers.net lub np. do Kompendium.

Wspomnienia użytkowników

By wspomnieć użytkownika forum, wpisz w formularzu znak @. Zobaczysz okienko samouzupełniające nazwy użytkowników. Samouzupełnienie dobierze odpowiedni format wspomnienia, zależnie od tego czy w nazwie użytkownika znajduje się spacja.

Znaczniki HTML

Dozwolone jest używanie niektórych znaczników HTML: <a>, <b>, <i>, <kbd>, <del>, <strong>, <dfn>, <pre>, <blockquote>, <hr/>, <sub>, <sup> oraz <img/>.

Skróty klawiszowe

Dodaj kombinację klawiszy komendą notacji klawiszy lub skrótem klawiszowym Alt+K.

Reprezentuj kombinacje klawiszowe używając taga <kbd>. Oddziel od siebie klawisze znakiem plus, np <kbd>Alt+Tab</kbd>.

Indeks górny oraz dolny

Przykład: wpisując H<sub>2</sub>O i m<sup>2</sup> otrzymasz: H2O i m2.

Składnia Tex

By precyzyjnie wyrazić działanie matematyczne, użyj składni Tex.

<tex>arcctg(x) = argtan(\frac{1}{x}) = arcsin(\frac{1}{\sqrt{1+x^2}})</tex>

Kod źródłowy

Krótkie fragmenty kodu

Wszelkie jednolinijkowe instrukcje języka programowania powinny być zawarte pomiędzy obróconymi apostrofami: `kod instrukcji` lub ``console.log(`string`);``.

Kod wielolinijkowy

Dodaj fragment kodu komendą . Fragmenty kodu zajmujące całą lub więcej linijek powinny być umieszczone w wielolinijkowym fragmencie kodu. Znaczniki ``` lub ~~~ umożliwiają kolorowanie różnych języków programowania. Możemy nadać nazwę języka programowania używając auto-uzupełnienia, kod został pokolorowany używając konkretnych ustawień kolorowania składni:

```javascript
document.write('Hello World');
```

Możesz zaznaczyć również już wklejony kod w edytorze, i użyć komendy  by zamienić go w kod. Użyj kombinacji Ctrl+`, by dodać fragment kodu bez oznaczników języka.

Tabelki

Dodaj przykładową tabelkę używając komendy . Przykładowa tabelka składa się z dwóch kolumn, nagłówka i jednego wiersza.

Wygeneruj tabelkę na podstawie szablonu. Oddziel komórki separatorem ; lub |, a następnie zaznacz szablonu.

nazwisko;dziedzina;odkrycie
Pitagoras;mathematics;Pythagorean Theorem
Albert Einstein;physics;General Relativity
Marie Curie, Pierre Curie;chemistry;Radium, Polonium

Użyj komendy by zamienić zaznaczony szablon na tabelkę Markdown.

Lista uporządkowana i nieuporządkowana

Możliwe jest tworzenie listy numerowanych oraz wypunktowanych. Wystarczy, że pierwszym znakiem linii będzie * lub - dla listy nieuporządkowanej oraz 1. dla listy uporządkowanej.

Użyj komendy by dodać listę uporządkowaną.

1. Lista numerowana
2. Lista numerowana

Użyj komendy by dodać listę nieuporządkowaną.

* Lista wypunktowana
* Lista wypunktowana
** Lista wypunktowana (drugi poziom)

Składnia Markdown

Edytor obsługuje składnię Markdown, która składa się ze znaków specjalnych. Dostępne komendy, jak formatowanie , dodanie tabelki lub fragmentu kodu są w pewnym sensie świadome otaczającej jej składni, i postarają się unikać uszkodzenia jej.

Dla przykładu, używając tylko dostępnych komend, nie możemy dodać formatowania pogrubienia do kodu wielolinijkowego, albo dodać listy do tabelki - mogłoby to doprowadzić do uszkodzenia składni.

W pewnych odosobnionych przypadkach brak nowej linii przed elementami markdown również mógłby uszkodzić składnie, dlatego edytor dodaje brakujące nowe linie. Dla przykładu, dodanie formatowania pochylenia zaraz po tabelce, mogłoby zostać błędne zinterpretowane, więc edytor doda oddzielającą nową linię pomiędzy tabelką, a pochyleniem.

Skróty klawiszowe

Skróty formatujące, kiedy w edytorze znajduje się pojedynczy kursor, wstawiają sformatowany tekst przykładowy. Jeśli w edytorze znajduje się zaznaczenie (słowo, linijka, paragraf), wtedy zaznaczenie zostaje sformatowane.

  • Ctrl+B - dodaj pogrubienie lub pogrub zaznaczenie
  • Ctrl+I - dodaj pochylenie lub pochyl zaznaczenie
  • Ctrl+U - dodaj podkreślenie lub podkreśl zaznaczenie
  • Ctrl+S - dodaj przekreślenie lub przekreśl zaznaczenie

Notacja Klawiszy

  • Alt+K - dodaj notację klawiszy

Fragment kodu bez oznacznika

  • Alt+C - dodaj pusty fragment kodu

Skróty operujące na kodzie i linijkach:

  • Alt+L - zaznaczenie całej linii
  • Alt+, Alt+ - przeniesienie linijki w której znajduje się kursor w górę/dół.
  • Tab/⌘+] - dodaj wcięcie (wcięcie w prawo)
  • Shit+Tab/⌘+[ - usunięcie wcięcia (wycięcie w lewo)

Dodawanie postów:

  • Ctrl+Enter - dodaj post
  • ⌘+Enter - dodaj post (MacOS)