“X = x ++” sonrasında x nedir?


285

Bu yapıldığında (perdelerin arkasında) ne olur?

int x = 7;
x = x++;

Yani, bir değişken yazı sonrası artırıldığında ve bir ifadede kendisine atandığında? Bunu derledim ve yürüttüm. tüm ifadeden sonra bilex hala 7 . Kitabımda, bunun arttığını söylüyor !x


9
Şunu deneyin:, int x = 7; x = ++x;elbette hala korkunç bir kod, yeniden atamanıza gerek yok. int x = 7; x++;yeterlidir.
stivlo

7
Bu gerçekten kötü bir uygulamadır, değişkeni kullandığınız satırda artırmayın.
Yousf

5
x += 1Belki döngüler dışında kullanmayı tercih ederim . for(int x=0; x<7; x++)
Svish

2
@andyortlieb nesne yok, sadece temel bir değer var.
fortran

Yanıtlar:


301

xartmaktadır. Ama sen eski xsırt değerini kendine atarsın.


x = x++;
  1. x++xeski değerini artırır ve döndürür.
  2. x = eski değeri kendine geri atar.

Sonunda, xbaşlangıç ​​değerine geri atanır.


3
Sonra x = ++ x hakkında ne söyleyeceksiniz;
Hisham Muneer

3
@HishamMuneer x, bu durumda okunmadan önce ilk olarak artırılır, böylece sonunda x + 1.

@HishamMuneer Çok geç. Ama buraya koyuyorum, çünkü geleceğe bakacak bazı insanlar için yararlı olabilir. Bu sorunun altında durmanın en iyi yolu x = x ++ ve x = ++ x için oluşturulan montaj koduna bakmaktır. Lütfen Thinkingcap'in cevabına da bakınız.
nantitv

Bunun çok eski olduğunu biliyorum, ama bir sorum var. Yukarıdaki çalışma sırası standart tarafından garanti ediliyor mu? Ödevin artıştan önce yürütülmesi mümkün müdür?
Zümrüt Silah

@EmeraldWeapon Java ile tanımlanmıştır. Sadece C / C ++ 'da bu tür maskaralık görüyorsunuz.
Mistik

385
x = x++;

eşittir

int tmp = x;
x++;
x = tmp;

46
Lol, özyinelemeli tanımlar için yay. Muhtemelen x=x+1yerine yapmalıydınx++
user606723

8
@ user606723: Hayır . x = x++Sadece yazı artışını değil , tüm ifadeyi kastediyorum x++.
Prens John Wesley

20
Daha fazla açıklama yapmadan bu kadar kullanışlı olduğunu düşünmüyorum. Örneğin, bununla x = ++x;eşdeğer olduğu doğru değildir int tmp = x; ++x; x = tmp;, bu yüzden hangi mantıkla cevabınızın doğru olduğunu (hangisi olduğunu) belirleyebiliriz?
kvb

4
daha da açıktır asm x=x++ =MOV x,tmp; INC x; MOV tmp,x
forker

3
@forker: Michael'ın kullandığı işlemciye uygulanan montaj talimatlarını kullanırsanız daha net olacağını düşünüyorum;)
Carl

258

İfade:

x = x++;

şuna eşittir:

tmp = x;   // ... this is capturing the value of "x++"
x = x + 1; // ... this is the effect of the increment operation in "x++" which
           //     happens after the value is captured.
x = tmp;   // ... this is the effect of assignment operation which is
           //     (unfortunately) clobbering the incremented value.

Kısacası, ifadenin bir etkisi yoktur.

Anahtar noktalar:

  • Postfix artış / azalış ifadesinin değeri , artış / azalış gerçekleşmeden önce işlenenin değeridir . (Önek formu durumunda, değer işlemden sonra işlenenin değeridir. )

  • Ödev ifadesinin RHS değeri, değer LHS'ye atanmadan önce tamamen (herhangi bir artış, azalma ve / veya diğer yan etkiler dahil) değerlendirilir .

C ve C ++ 'dan farklı olarak, Java'daki bir ifadenin değerlendirme sırasının tamamen belirtildiğini ve platforma özgü varyasyon için yer olmadığını unutmayın. Derleyicilerin işlemleri yalnızca kodun yürürlükteki iş parçacığının bakış açısından değiştirmemesi durumunda yeniden sıralamasına izin verilir. Bu durumda, bir derleyicinin tüm ifadeyi optimize etmesine izin verilecektir, çünkü bunun bir işlem yapılmadığı kanıtlanabilir.


Zaten açık değilse:

  • "x = x ++;" herhangi bir programda neredeyse kesinlikle bir hatadır.
  • OP (orijinal soru için!) Muhtemelen "x ++;" "x = x ++;" yerine.
  • Otomatik değişkenlik / azalış ve aynı değişken üzerinde atamayı birleştiren ifadelerin anlaşılması zordur ve bu nedenle bunların doğruluğuna bakılmaksızın kaçınılmalıdır . Böyle bir kod yazmaya gerek yoktur.

Umarım FindBugs ve PMD gibi kod denetleyicileri bu kodu şüpheli olarak işaretler.


7
Bir yan not olarak, OP, muhtemelen x++yerine söylemek istersiniz x = x++.
Jon Newmuis

3
Doğru, ama belki artışın sağ ifade ekspresyonu sonrası gerçekleştiğini vurgulayın , ancak sol tarafa ön atama, dolayısıyla görünen "üzerine yazma"
Bohemian

2
bu lise programlama bükümlerinden biri gibi görünüyor ... temellerinizi temizlemek için iyi!
kumarharsh

1
@Alberto - "Uzman" ifadelerini "müjde gerçeği" olarak almadığınızı duymak güzel. Ancak, söylediklerimi doğrulamanın daha iyi bir yolu JLS'ye danışmak olacaktır. Derleme / derleme testiniz yalnızca söylediğim şeyin bir Java derleyicisi için geçerli olduğunu gösterir. Diğerleri (varsayımsal olarak) farklı davranabilirdi ... ancak JLS buna izin vermiyor.
Stephen C

4
Sadece bir FYI: Bu aslında farklı bir soruya gönderildi, bu da bunun bir kopyası olarak kapatıldı ve şimdi birleştirildi.
Shog9

33
int x = 7;
x = x++;

C'de tanımlanmamış bir davranışa sahiptir ve Java için bu yanıta bakın . Derleyiciye ne olduğuna bağlıdır.


4
Hayır, alıntıladığınız yanıta göre derleyiciye bağlı değil - lütfen düzenleyin - şimdilik
Mr_and_Mrs_D

@Mr_and_Mrs_D O zaman neye bağlı?
Mac

2
C_ için tanımlanmamış davranış_onaldır. Buna rağmen derleyiciye bağlı olduğunu söylemek yanıltıcıdır - derleyicinin bu davranışı belirtmesi gerektiğini ima eder. Oyumu geri alıyorum ama cevabınızı düzenlemeyi düşünün - edit: oops
Yapamıyorum

16

Benzeri bir yapı x = x++;, muhtemelen ++operatörün yaptıklarını yanlış anladığınızı gösterir :

// original code
int x = 7;
x = x++;

++Operatörü kaldırmaya dayalı olarak aynı şeyi yapmak için bunu yeniden yazalım :

// behaves the same as the original code
int x = 7;
int tmp = x; // value of tmp here is 7
x = x + 1; // x temporarily equals 8 (this is the evaluation of ++)
x = tmp; // oops! we overwrote y with 7

Şimdi istediğinizi yapmak için yeniden yazalım (istediğimi):

// original code
int x = 7;
x++;

Burada incelik olduğunu ++operatör değiştirir değişkenx gibi bir ifadesi aksine x + xint değerine değerlendirmek ancak değişken bırakacaktı, xkendisi değişmez. Saygıdeğer fordöngü gibi bir yapı düşünün :

for(int i = 0; i < 10; i++)
{
    System.out.println(i);
}

Dikkat i++orada? Aynı operatör. Bu fordöngüyü böyle yeniden yazabiliriz ve aynı şekilde davranır:

for(int i = 0; i < 10; i = i + 1)
{
    System.out.println(i);
}

Ayrıca ++çoğu durumda operatörü daha büyük ifadelerde kullanmamanızı öneririm . Çünkü incelik zaman o ön karşı sonrası artış (orijinal değişken değiştirir ++xve x++sırasıyla), çok kolay izini zordur ince böcek tanıtmaktır.


13

Sınıf dosyalarından alınan Bayt koduna göre ,

Her iki atama da x değerini artırır ancak fark, when the value is pushed onto the stack

Konumunda Case1, Push artıştan önce gerçekleşir (ve daha sonra atanır) (esas olarak artışın hiçbir şey yapmaz)

İçinde Case2, önce Artış gerçekleşir (8 yapar) ve ardından yığına itilir (ve sonra x'e atanır)

Dava 1:

int x=7;
x=x++;

Bayt Kodu:

0  bipush 7     //Push 7 onto  stack
2  istore_1 [x] //Pop  7 and store in x
3  iload_1  [x] //Push 7 onto stack
4  iinc 1 1 [x] //Increment x by 1 (x=8)
7  istore_1 [x] //Pop 7 and store in x
8  return       //x now has 7

Durum 2:

int x=7; 
x=++x;

Bayt Kodu

0  bipush 7     //Push 7 onto stack
2  istore_1 [x] //Pop 7 and store in x
3  iinc 1 1 [x] //Increment x by 1 (x=8)
6  iload_1  [x] //Push x onto stack
7  istore_1 [x] //Pop 8 and store in x
8  return       //x now has 8
  • Buradaki yığın Operand Stack'i belirtir, local: x index: 1 type: int

Lütfen cevabınızı ayrıntılı olarak açıklar mısınız?
Nihar

Pls referans verilen bağlantı ve yorumlara bir göz atın
evenprime

8

" x = x++;" Den sonra artırıldı . " x = ++x;" Yaparsanız 8 olurdu .


4
Daha sonra artırılırsa x = x++, 8 olmalıdır.
R. Martinho Fernandes

8

Artım Sonrası işleci aşağıdaki gibi çalışır:

  1. İşlenenin önceki değerini depola.
  2. İşlenenin değerini artırın.
  3. İşlenenin önceki değerini döndür.

Yani ifade

int x = 7;
x = x++; 

aşağıdaki gibi değerlendirilecektir:

  1. x değeri 7 değeriyle başlatılır
  2. artım sonrası operatörü döndürülecek önceki x yani 7 değerini saklar.
  3. X değerini artırır, bu nedenle x şimdi 8'dir
  4. Önceki x yani 7 değerini döndürür ve x'e geri atanır, böylece x tekrar 7 olur

Yani x gerçekten artar, ancak x ++ sonucu tekrar x'e atadığı için x değeri önceki değerine göre geçersiz kılınır.


Ama msvc x'de 8'dir. Evet, gcc ve clang'da 7 7'dir.
Summer Sun

7

Artış x çağrıldıktan sonra gerçekleşir, bu nedenle x hala 7'ye eşittir. X x çağrıldığında x + x 8 olur


7

Değerini yeniden atadığınızda xhala 7 olur. Deneyin x = ++xve 8 tane daha alacaksınız

x++; // don't re-assign, just increment
System.out.println(x); // prints 8

6

çünkü x ++, değişkene atandıktan SONRA değerini artırır. ve bu satırın yürütülmesi sırasında:

x++;

x değişkeni hala orijinal değere (7) sahip olur, ancak x'i başka bir satırda tekrar kullanmak gibi, örneğin

System.out.println(x + "");

size 8 verecek.

atama ifadenizde x değerinin artış değerini kullanmak istiyorsanız şunu kullanın:

++x;

Bu, x'i 1 artırır, daha sonra bu değeri x değişkenine atar.

X = x ++ yerine [Düzenle], sadece x ++; birincisi x'in orijinal değerini kendisine atar, bu yüzden aslında bu satırda hiçbir şey yapmaz.


Atamadan sonra arttığını söyleyen ve yazdıracağını söyleyen 8 yazdırır. Atamadan önce artar ve 7 yazdırır.
R. Martinho Fernandes

x aslen 7 ise, System.out.println (String.valueOf (x ++)); 7. Aynı programlama dilinden bahsettiğimizden emin misiniz?
josephus

Evet benim. Bu ideone.com/kj2UU , bu yanıt iddialarında olduğu gibi 8 yazdırmıyor.
R. Martinho Fernandes

evet, yanılmışım. x = x ++, x değerini artırmadan önce 7'ye x değerini atayacaktır. x ++ (kendi başına bir atamadır) önce x = (ne olursa olsun) önce çözülürken, x = (ne olursa olsun) x'e atanan değer gelecektir. üzgünüm bunu görmedim.
josephus

1
Aslında, artış ilk gerçekleşen şeydir . ideone.com/xOIDU
R. Martinho Fernandes

4

Ne zaman olur int x = 7; x = x++;?

ans -> x++ifadesi için x'in ilk kullanım değeri anlamına gelir ve daha sonra bunu 1 arttırır
. RHS üzerindeki x değeri, LHS üzerindeki x değişkenine kopyalanır ve sonra değeri x1 arttırılır.

Benzer şekilde , x'in değerini önce birer birer arttırmak ve sonra ifadede kullanmak ++x anlamına gelir ->.
Yani sizin durumunuzda yaparsanız x = ++x ; // where x = 7
8 değerini alacaksınız.

Daha fazla netlik için aşağıdaki kodun kaç printf deyimini çalıştıracağını bulmaya çalışın

while(i++ <5)   
  printf("%d" , ++i);   // This might clear your concept upto  great extend

doğru değil "RHS'deki x değeri LHS üzerindeki x değişkenine kopyalanır ve sonra x değeri 1 arttırılır" - bu x8 olur, ancak 7 - okuma ve atama arasında artış olur
user85421

3

++xartım öncesi ->x kullanılmadan önce
x++ artırılır ->artım sonrası x kullanıldıktan sonra arttırılır

int x = 7; -> x get 7 value <br>
x = x++; -> x get x value AND only then x is incremented

1

Bu yollarla Yani: x++eşit değildirx = x+1

Çünkü:

int x = 7; x = x++;
x is 7

int x = 7; x = x = x+1;
x is 8

ve şimdi biraz garip görünüyor:

int x = 7; x = x+=1;
x is 8

çok derleyiciye bağımlı!


2
ilk etapta eşit olduğunu kim söyledi?
fortran

1
Ben olsaydım bu kitapları hemen çöpe atardım Her durumda, (x = x + 1, x-1)virgülle ayrılmış ifadelere izin verilen C'deki gibi olurdu .
fortran

3
@fortran: "Java Programlama Dili, Üçüncü Baskı" nın on yıllık kopyasımda "159 i ifadesi, i = i + 1 ile eşdeğerdir, ancak i yalnızca bir kez değerlendirilir" der. İlk etapta? James Gosling, görünecektir.Java spec'in bu baskısının bu kısmı olağanüstü belirsiz ve kötü bir şekilde belirtilmiştir; Daha sonraki sürümlerin gerçek operatör semantiğini daha net ifade etmek için dili temizlediğini
varsayıyorum

2
@fortran: "i dışında sadece bir kez değerlendirilir" ile standart "M () .x ++" gibi bir ifadenin sadece M () 'yi çağırdığını söylemeye çalışır. Daha az muğlak ve daha doğru ifadeler arasında bir fark olduğunu vurgulamak istiyorum depolama konumunu belirlemek için bir değişken olarak i değerlendirerek burada ne "sadece bir kez değerlendirilir" kastedilen şey - - ve okuma veya bu depolama konumuna yazma - - her ikisi de 'değerlendirilmiş' olmanın makul fakat yanlış bir yorumu olabilir. Açıkçası depolama yeri hem okunmalı hem de yazılmalıdır!
Eric Lippert

1
"derleyiciye bağımlı" - Hiç değil!
Stephen C

-1

x = x ++;

Bu artım sonrası operatörüdür. "İşlenenin değerini kullan ve sonra işlenmeyi artır" şeklinde anlaşılmalıdır.

Bunun tersinin gerçekleşmesini istiyorsanız, yani "İşleneni artırın ve sonra işlenenin değerini kullanın", aşağıda gösterildiği gibi artış öncesi operatörünü kullanmalısınız.

x = ++ x;

Bu işleç önce x değerini 1 artırır ve ardından değeri tekrar x değerine atar.


-1

Bu tartışmanın koda girmeden ve sadece düşünmeden çözülebileceğini düşünüyorum.

İşlev olarak i ++ ve ++ i düşünün, örneğin Func1 ve Func2.

Şimdi i = 7;
Func1 (i ++) 7 döndürür, Func2 (++ i) 8 döndürür (herkes bunu bilir). Dahili olarak her iki fonksiyon da i'yi 8'e çıkarır, ancak farklı değerler döndürürler.

Yani i = i ++ Func1 işlevini çağırır. İ işlevinin içinde 8'e çıkar, ancak tamamlandığında işlev 7 değerini döndürür.

Sonuçta 7 i'ye ayrılır. (Sonuçta, i = 7)


2
Burada geçerli bir "tartışma" yoktur. Kod açıkça belirli bir şekilde davranır ve davranış JLS'ye uygundur. Farklı davrandığını düşünen herkes ya bunu denemedi ya da kandırıldı. (Bu, birileri zaman tablolarını unuttuğunda 7 x 7'nin 49 olduğunu "tartışmalı" demek gibi bir şey ...)
Stephen C

-2

Bunun sebebi bir artım sonrası operatörü kullanmanızdır. Aşağıdaki kod satırında

x = x++;

Ne oluyor, x'e x değerini atarsınız. x ++, x değeri x'e atandıktan sonra x değerini artırır. Artım sonrası operatörler bu şekilde çalışır. Bir ifade yürütüldükten sonra çalışırlar. Kodunuzda, x ilk olarak sonradan döner, sonra artar.

Eğer yaptıysan

x = ++x;

Yanıt 8 olacaktır, çünkü artış öncesi operatörünü kullandınız. Bu, x değerini döndürmeden önce değeri artırır.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.