C ++ 'da “->” operatörü nedir?


8925

Okuduktan sonra Gizli Özellikleri ve C ++ / STL Dark Corners üzerine comp.lang.c++.moderated, tamamen aşağıdaki derlenmiş ve Visual Studio 2008 ve G ++ 4.4 hem çalıştı snippet'ine olduğu şaşırdı.

İşte kod:

#include <stdio.h>
int main()
{
    int x = 10;
    while (x --> 0) // x goes to 0
    {
        printf("%d ", x);
    }
}

Çıktı:

9 8 7 6 5 4 3 2 1 0

Bunun C olduğunu varsayacağım, çünkü GCC'de de çalışıyor. Bu standartta nerede tanımlanır ve nereden gelir?


503
Ya da sadece uygun boşluklar bile ... Değişkenler arasında ya ++da daha --önce bir boşluk gördüğümü sanmıyorum ...
Matthew Scharley

1154
Bu "gider" operatörü geri alınabilir (0 <- x). Ve ayrıca bir "çalışır" operatörü vardır (0 <---- x). Geez, soru için c ++ sözdizimi =) +1 olarak duyduğum en komik şey.
SadSido

233
Ne kadar garip ki, yorum çok yanlış olsa da, kodun doğru bir şekilde ne yaptığını anlatıyor. :)
Noldorin

811
Yeni sözdizimi olasılıklarını hayal edin: #define upto ++<, #define downto -->. Kötülük hissediyorsanız, yapabilir #define for while(ve #define do ) {(ve #define done ;}) ve for x downto 0 do printf("%d\n", x) doneOh, insanlığı yazabilirsiniz ...
Chris Lutz

98
Yepyeni etkileyici bir kodlama yolu olasılığını açar, aşağıdakiler için birkaç derleyici uyarısını feda etmeye değer: bool CheckNegative (int x) {return x <0? doğru yanlış ); }
ttt

Yanıtlar:


8603

-->bir operatör değil. Aslında iki ayrı operatör, --ve >.

Koşulun kodu x, xorijinal (azaltılmamış) değeri döndürülürken azalır ve ardından orijinal değeri işleci 0kullanarak karşılaştırır >.

Daha iyi anlamak için ifade aşağıdaki gibi yazılabilir:

while( (x--) > 0 )

262
Sonra tekrar, bu bağlamda bir çeşit menzil operatörü gibi görünüyor.
Charles Salvia

109
X değerinin sonradan azaltıldığını ve ardından 0 ile karşılaştırıldığını söylemek, x'in 0 ile karşılaştırıldıktan sonra azaltıldığını söylemekle aynıdır
Charles Salvia

8
Aynı olduğunu sanmıyorum. Bence "o zaman" kelimesi bir emir olduğunu ima eder (post decrementing sonra x'in değeri bir daha azdır). Bence daha net hale getirmek için "Sen x azaltma sonrası ve sonra eski değeri ve 0 ... karşılaştırmak" diyebilirsiniz. Ama bu yine de nitpick. Ne anlama geldiğini hepimiz biliyoruz.
Johannes Schaub - litb

38
Java da derler :)
Steven Devijver

44
Adı @Jay, kötü programlama tarzı :-) Bu sorunun ilk etapta sorulduğu gerçeği ile kanıtlanmıştır. Operatörleri ilgisiz bir şey yerine, üzerinde çalıştıkları şeye metinsel olarak bağlamak çok daha mantıklıdır, bu yüzden while (x-- > 0)daha uygun olacaktır. Ayrıca, neler olduğunu (en azından sabit yazı tipi düzenleyicide) daha açık hale getirir, bu da bu yanıttaki parantezlerin gerekli olmayacağı anlamına gelir.
paxdiablo

3131

Ya da tamamen farklı bir şey için ... xkayar 0.

while (x --\
            \
             \
              \
               > 0)
     printf("%d ", x);

O kadar matematiksel değil, ama ... her resim bin kelimeyi boyar ...


216
@mafutrct - Hatırladığım kadarıyla C'de \ bir sonraki satırı bir satır sonu yokmuş gibi ekler. Burada \ 'ın temelde hiçbir şey yapmayın.
Hogan

2
@mafu '\' karakteri derleyiciye geçerli satırın bir sonraki satırda devam ettiğini söyler ve böylece derleyici her iki satırı birleştirmeli ve bir olarak derlemelidir. 'while (x -> 0)', x -1'e eşit olana kadar çalışır. Ancak, girintileri yapma şekli x'i sıfıra doğru kaydırıyor. 'X 0'a kayarken'
Felype

16
IIRC, K&R C, eksiltme operatörünün '-'ler arasında boşluk bırakmasına izin verdi, bu durumda, daha da havalı görünecek olan ortasında ters eğik çizgiler olabilir. :)
Jules

10
@ArnavBorborah why waste words when a picture does a better jobBu bağlamda şaka olarak kullanılan eski bir ifade anlamı . (aslında 2 anahtar kelime vardır whileve printf)
senkronize olmayan

88
Ah evet, karanlık slayt operatörü. Nasıl unutabilirim!
demonkoryu

2377

Bu çok karmaşık bir operatör, bu nedenle ISO / IEC JTC1 (Ortak Teknik Komite 1) bile açıklamasını C ++ Standardının iki farklı bölümüne yerleştirdi.

Şaka bir yana, bunlar iki farklı operatördür: --ve >sırasıyla C ++ 03 Standardının §5.2.6 / 2 ve §5.9'larında açıklanmıştır.


1277

Eşittir

while (x-- > 0)

x--(azaltma sonrası) buna eşdeğerdir x = x-1, kod şuna dönüşür:

while(x > 0) {
    x = x-1;
    // logic
}
x--;   // The post decrement done when x <= 0

15
Bu pek doğru değil. Döngü gövdesinin içindeki x değeri ikinci durumda farklıdır. Örneğinizdeki atama ifadesi, eşdeğer olması için mantığın üstünde olmalıdır . Postfix - 1 çıkarır, ancak karşılaştırma çıkarmadan önceki değerle gerçekleşir .
uliwitness

4
@uliwitness Bunlar gerçekten eşdeğerdir. Önek kullanılıyorsa yanlış olur: 0 >-- xBu durumda xmantıktan önce azaltılır. Düzeltme sonrası, mantık azalmadan önce yürütülür ve böylece her iki örnek de eşdeğerdir. Onları a yazıp Consoletest etmekten çekinmeyin .
Candleshark

12
Hala eşdeğer değiller. İlk döngüden sonra, x -1'dir (veya imzasız olması durumunda taşar), ikinciden sonra 0 olur. (X'in negatif olmayan olarak başladığı varsayıldığında, hiçbir döngü x'i değiştirmez veya kesmez veya…)
Sezar

1
while(x=x-1,x+1 > 0)eşdeğerdir.
SS Anne

2
@Shebham, İşte bir karşı örnek: x 0 olarak başlarsa, orijinal döngü altında -1 olarak çıkar, sürümünüzle birlikte sıfır kalır. Yani eşdeğer değiller.
Elliott

1208

x ters yönde daha da sıfıra gidebilir:

int x = 10;

while( 0 <---- x )
{
   printf("%d ", x);
}

8 6 4 2

Hızı bir ok ile kontrol edebilirsiniz!

int x = 100;

while( 0 <-------------------- x )
{
   printf("%d ", x);
}

90 80 70 60 50 40 30 20 10

;)


6
hangi işletim sistemi, üretilen çıktı bu tür, ben bir hata mesajı vardı ki bir ubuntu 12.04 kullanıyorum
Bhuvanesh

74
Açık olsa da, C ++ 'da yeni olan herkes için bunu okuyan: yapma. Birden fazla artırmanız / azaltmanız gerekiyorsa, artırılmış ödevi kullanın.
Blimeo

263
"Lazerler" ile sıfır. (0> - - - - - - - - - - ---------- x) ... aynı çıkış.
Samuel Danielson

4
@phord derlemediğinden emin misin? -> coliru.stacked-crooked.com/a/5aa89a65e3a86c98
doc

18
@doc c ++ 'da derler, ancak c'de derlemez.
16'da phord

548

Onun

#include <stdio.h>
int main(void){
     int x = 10;

     while( x-- > 0 ){ // x goes to 0

       printf("%d ", x);
     }

     return 0;
}

Sadece alan şeylerin komik görünmesini sağlar, --azalır ve >karşılaştırır.


431

Kullanımının -->tarihsel önemi vardır. Azaltma, (ve bazı durumlarda hala) x86 mimarisinde artıştan daha hızlıydı. Kullanılması -->düşündürmektedir xgidiyor 0matematiksel kökenden olanlara, ve itirazlar.


479
Tam olarak doğru değil. Azalan ve Artan aynı zaman alır, bunun yararı sıfıra karşılaştırmanın bir değişkene kıyasla karşılaştırmaya göre çok hızlı olmasıdır. Bu sadece x86 için değil, birçok mimaride geçerlidir. JZ talimatı olan herhangi bir şey (sıfır ise atlama). Etrafta dolaşmak, karşılaştırmalarda döngüleri kaydetmek için geriye doğru yazılmış birçok "for" döngüsünü bulabilirsiniz. Bu özellikle x86'da hızlıdır, çünkü değişkenin azaltılması eylemi sıfır bayrağını uygun şekilde ayarlar, böylece daha sonra değişkeni açıkça karşılaştırmak zorunda kalmadan dallayabilirsiniz.
burito

25
Sıfıra doğru azaltmak, döngü yinelemesi başına sadece 0 ile karşılaştırmanız gerektiği anlamına gelirken, n'ye yineleme, her yinelemeyle n karşılaştırması anlamına gelir. Birincisi daha kolay olma eğilimindedir (ve bazı mimarilerde her veri kaydı işleminden sonra otomatik olarak test edilir).
Joey Adams

9
@burrito Katılmama rağmen, sıfırdan farklı değerlere dayalı döngüler genellikle mükemmel bir şekilde tahmin edilir.
Duncan

14
Artış ve azalma, muhtemelen tüm platformlarda (kesinlikle x86'da) eşit derecede hızlıdır. Fark, döngü sonu koşulunun test edilmesidir. Sayacın sıfıra ulaşıp ulaşmadığını görmek için ücretsizdir - bir değeri düşürdüğünüzde, işlemcide bir sıfır işareti ayarlanır ve bitiş koşulunu tespit etmek için sadece o bayrağı kontrol etmeniz gerekirken, son koşuldan önce bir karşılaştırma işlemi gerekir. tespit edilebilir.
lego

7
Tabii ki, tüm bunlar bugünlerde tartışmalı, çünkü modern derleyiciler döngüleri otomatik olarak vektörleştirebilir ve tersine çevirebilir.
Lambda Fairy


362

Tamamen inek, ama bunu kullanacağız:

#define as ;while

int main(int argc, char* argv[])
{
    int n = atoi(argv[1]);
    do printf("n is %d\n", n) as ( n --> 0);
    return 0;
}


1
Bu derlenmiyor. C, iç kısmı do ... whilebir ifade listesi olan Pascal değildir . C'de bu bir bloktur, öyle olması gerekir do { ... } while.
user207421

25
@EJP derleme yapar. Sözdizimi do statement while ( expression ) ;. Bunu söyledikten sonra, umarım anlaşılmaktadır ki örnek şaka olarak kastedilmiştir.
Escualo

321

Okuduğum bir kitap (hangi kitabı doğru hatırlamıyorum) ifade etti: Derleyiciler , sol sağ kuralı kullanarak ifadeleri en büyük jetonla ayrıştırmaya çalışırlar .

Bu durumda, ifade:

x-->0

En büyük jetonlara ayrıştırma:

token 1: x
token 2: --
token 3: >
token 4: 0
conclude: x-- > 0

Aynı kural bu ifade için de geçerlidir:

a-----b

Ayrıştırmadan sonra:

token 1: a
token 2: --
token 3: --
token 4: -
token 5: b
conclude: (a--)-- - b

Umarım bu karmaşık ifadeyi anlamaya yardımcı olur ^^


98
İkinci açıklamanız doğru değil. Derleyici görecek a-----bve düşünecek (a--)-- - b, ki bu bir derleme a--döndürmediği için derlenmiyor.
Tim Leaf

22
Ayrıca xve --iki ayrı token.
Roland Illig

23
@DoctorT: lexer'ı geçer. yalnızca semantik geçiş bu hatayı yayınlayabilir. bu yüzden açıklaması doğru.
v.oddou

9
-->Bir operatör olduğunu düşündüğünüz sürece (sorulan soru ile ima edilen şey budur), bu cevap hiç yardımcı değildir - token 2'nin -->sadece olduğunu düşünmeyeceksiniz --. Bir -->operatör olmadığını biliyorsanız, muhtemelen sorudaki kodu anlamada bir sorununuz yoktur, bu yüzden tamamen farklı bir sorunuz yoksa, bunun nasıl yararlı olabileceğinden gerçekten emin değilim.
Bernhard Barker

4
@DoctorT örneği, lvalue adöndüren, azaltma sonrası operatörün aşırı yüklü olduğu varsayılarak doğru olabilir . coliru.stacked-crooked.com/a/e1effc351ae79e9f
doc


242

Her neyse, şimdi "gider" operatörü var. "-->"bir yön olarak hatırlanması kolaydır ve "x sıfıra giderken" düz anlamlıdır.

Ayrıca, "for (x = 10; x > 0; x --)"bazı platformlardan biraz daha verimlidir .


17
Özellikle x değeri negatif olduğunda her zaman doğru olamaz.
Ganesh Gopalasubramanian

15
Diğer sürüm aynı şeyi yapmaz - for (size_t x=10; x-->0; )döngünün gövdesi 9,8, .., 0 ile yürütülürken, diğer sürüm 10,9, .., 1'dir. Aksi halde işaretsiz bir değişkenle sıfıra inmek oldukça zor.
Pete Kirkham

4
Bence bu biraz yanıltıcı ... Kelimenin tam anlamıyla "gidecek" bir operatöre sahip değiliz, çünkü ++>artımlı işi yapmak için bir başkasına ihtiyacımız var .
tslmy

19
@Josh: aslında, taşma tanımsız davranışlar verir int, bu yüzden xnegatif başlarsa köpeğinizi sıfıra almak kadar kolay yiyebilir .
SamB

3
@PeteKirkham tarafından komodinde verilen nedenden dolayı bu benim için çok önemli bir deyim, çünkü çoğu zaman imzasız miktarlar üzerinde sonuna kadar azalan döngüler yapmam gerekiyor 0. (Karşılaştırma için, bu tür yazma olarak sıfır testleri, omitting deyim while (n--)imzasız yerine n, alımlara sana hiç bir şey ve benim için büyük ölçüde okunabilirliği güçleştirmektedir.) Ayrıca belirttiğiniz hoş özelliği vardır daha birini genellikle ne olduğunu ilk endeks, daha istediğiniz (ör. dizinin üzerindeki bir döngü için boyutunu belirtin). -->Boşluksuz olmayı da seviyorum , çünkü bu deyimi tanımayı kolaylaştırıyor.
Marc van Leeuwen

221

Bu kod önce x ve 0'ı karşılaştırır, sonra x'i azaltır. (Ayrıca ilk cevapta da söylendi: x >değerini azaltma ve x ile 0'ı operatörle karşılaştırma.) Bu kodun çıktısına bakın:

9 8 7 6 5 4 3 2 1 0

Şimdi çıktıda 0'ı görerek önce karşılaştırıyoruz ve azalıyoruz.

Önce azaltmak ve sonra karşılaştırmak istiyorsak, bu kodu kullanın:

#include <stdio.h>
int main(void)
{
    int x = 10;

    while( --x> 0 ) // x goes to 0
    {
        printf("%d ", x);
    }
    return 0;
}

Bu çıktı:

9 8 7 6 5 4 3 2 1

177

Bu kodu çalıştırdığımda derleyicim 9876543210 yazdıracak.

#include <iostream>
int main()
{
    int x = 10;

    while( x --> 0 ) // x goes to 0
    {
        std::cout << x;
    }
}

Beklenildiği gibi. while( x-- > 0 )Aslında demektir while( x > 0). x--Sonrası azaltır x.

while( x > 0 ) 
{
    x--;
    std::cout << x;
}

aynı şeyi yazmanın farklı bir yoludur.

Yine de orijinalin "x 0'a giderken" gibi olması güzel.


4
Sonuç, yalnızca aynı ifadede aynı değişkeni bir kereden fazla artırdığınızda / azalttığınızda tanımsızdır. Bu durum için geçerli değildir.
Tim Leaf

13
while( x-- > 0 ) actually means while( x > 0)- Orada ne demeye çalıştığınızdan emin değilim, ama bunu ifade etme şeklinizin --hiçbir anlamı olmadığı anlamına geliyor, ki bu çok yanlış.
Bernhard Barker

Noktayı eve @Dukeling'den sürmek için, bu cevap orijinal gönderiyle aynı değildir . Orijinal gönderide, döngüden ayrıldıktan sonra xolacak -1, bu cevapta xolacak 0.
Mark Lakata

148

--Ve arasında eksik bir boşluk var >. xsonrası azaltılır, yani durumu kontrol ettikten sonra azaltılır x>0 ?.


42
Boşluk eksik - C (++) boşlukları yok sayar.

27
@ H2CO3 Bu genel olarak doğru değil. Örneğin beyaz boşluk ayrı jeton için kullanılmalıdır yer vardır #define foo()karşı #define foo ().
Jens

30
@Jens Nasıl olur: "Alan eksik değil - C (++) gereksiz beyaz alanı yok sayar."?
Kevin P. Rice

139

--bir eksiltme operatörü >olan büyüktür operatör.

İki operatör tek bir tane gibi uygulanır -->.


11
Onlar ediyoruz uygulanan oldukları 2 ayrı operatörler olarak. Sadece yanıltıcı biçimde "tek bir taneye" benzemek için yazılırlar .
underscore_d

129

İki operatörün bir kombinasyonu. Birincisi --, değeri azaltmak ve değerin >sağ taraftaki işlenenden daha büyük olup olmadığını kontrol etmektir.

#include<stdio.h>

int main()
{
    int x = 10;

    while (x-- > 0)
        printf("%d ",x);

    return 0;
}

Çıktı şöyle olacaktır:

9 8 7 6 5 4 3 2 1 0            

122

Aslında, xazalmadan sonra ve bu durum kontrol ediliyor. Değil -->, değil(x--) > 0

Not: değeri x, koşul kontrol edildikten sonra değiştirilir, çünkü azalmadan sonra. Bazı benzer durumlar da ortaya çıkabilir, örneğin:

-->    x-->0
++>    x++>0
-->=   x-->=0
++>=   x++>=0

6
Bunun dışında ++> bir süre () kullanılamaz. Bir "yukarı gider ..." operatörü ++ <olur, ki bu hiç hoş görünmüyor. Operatör -> mutlu bir tesadüf.
Florian F

2
@BenLeggiero Bu, bir şey yapan kod üretme anlamında 'işe yarayabilir' (sahte akıllı kodu sevmeyen okuyucuları çileden çıkarırken), ancak anlambilim farklıdır, çünkü öngörü kullanımı daha az yineleme uygulayacağı anlamına gelir. Bir örnek olarak, x1'den başlarsa döngü gövdesini asla yürütmez , ama yapar while ( (x--) > 0 ). {edit} Eric Lippert her ikisi de C # 4 sürüm notlarında yer aldı: blogs.msdn.microsoft.com/ericlippert/2010/04/01/…
underscore_d

120

C ve C ++ , "maksimum munch" kuralına uyar. Aynı şekilde --- b'ye çevrilir (a--) - b, sizin durumunuzda da x-->0tercüme edilir (x--)>0.

Kuralın temelde söylediği şey, soldan sağa doğru, ifadelerin geçerli bir ifade oluşturacak maksimum karakter alınarak oluşturulur.


5
OP'nin varsaydığı şey buydu: "((a) ->)" maksimum munch'du. OP'nin orijinal varsayımının yanlış olduğu ortaya çıktı: "->" maksimum geçerli bir operatör değil.
david

4
Doğru hatırlıyorsam, açgözlü ayrıştırma olarak da bilinir.
Roy Tinker

1
@RoyTinker Açgözlü tarama. Ayrıştırıcının bununla hiçbir ilgisi yoktur.
user207421

27

Neden tüm komplikasyon?

Orijinal sorunun basit cevabı şudur:

#include <stdio.h>
int main()
{
    int x = 10;
    while (x > 0) 
    {
        printf("%d ", x);
        x = x-1;
    }
}

Aynı şeyi yapar. Bunu böyle yapmanız gerektiğini söylememek, ama aynı şeyi yapar ve soruyu bir gönderide cevaplardı.

Yukarıdaki x--sadece kısayol ve >normalden daha büyük operator. Büyük gizem yok!

Günümüzde basit şeyleri karmaşık hale getiren çok fazla insan var;)


17
Bu soru komplikasyonlarla ilgili değil, ** C ++ / STL'nin ** Gizli Özellikleri ve Karanlık Köşeleri **
pix

20
Buradaki program orijinalden farklı çıktı verir, çünkü burada printf'den sonra x azaltılır. Bu, "basit cevaplar" ın genellikle Yanlış olduğunu iyi gösterir.
Öö Tiib

2
The OP's way: 9 8 7 6 5 4 3 2 1 0veThe Garry_G way: 10 9 8 7 6 5 4 3 2 1
Anthony

2
Aynı şeyi yapmaz. x=x-1Önce hareket printfsonra "aynı şeyi yapar" diyebilirsiniz.
CITBL

26

Geleneksel yolla, whiledöngü parantezinde bir koşul ve parantez içindeki ()bir sonlandırma koşulu tanımlayacağız {}, ancak -->ikisini birden tanımlayacağız.

Örneğin:

int abc(void)
{
    int a = 5
    while((a--) > 0) // Decrement and comparison both at once
    {
        // Code
    }
}

Bu adöngü adaha büyükken döngüyü azaltır ve çalıştırır 0.

Geleneksel olarak şöyle olur:

int abc(void)
{
    int a = 5;
    while(a > 0)
    {
        a--;
        // Code
    }
    a--;
}

Her iki şekilde de aynı şeyi yapıyoruz ve aynı hedeflere ulaşıyoruz.


5
Bu yanlış. Sorudaki kod şunları yapar: 'test-write-execute' (önce test, yeni değer yaz, döngüyü yürüt), örneğiniz 'test-execute-write' dır.
v010dya

@ v010dya Yanıt düzeltildi, şimdi test-write-executesoruda olduğu gibi, işaret ettiğiniz için teşekkürler!
Kotauskas

@VladislavToncharov Düzenlemeniz hala yanlıştı. Benimkini gör.
SS Anne

8

(x --> 0) anlamına geliyor (x-- > 0)

  1. kullanabilirsiniz (x -->)
    output -: 9 8 7 6 5 4 3 2 1 0

  2. Kullanabileceğiniz (-- x > 0) Bu kötü biri(--x > 0)
    output -: 9 8 7 6 5 4 3 2 1

  3. kullanabilirsiniz
(--\
    \
     x > 0)

output -: 9 8 7 6 5 4 3 2 1

  1. kullanabilirsiniz
(\
  \
   x --> 0)

output -: 9 8 7 6 5 4 3 2 1 0

  1. kullanabilirsiniz
(\
  \
   x --> 0
          \
           \
            )

output -: 9 8 7 6 5 4 3 2 1 0

  1. ayrıca kullanabilirsiniz
(
 x 
  --> 
      0
       )

output -: 9 8 7 6 5 4 3 2 1 0

benzer şekilde, bu komutu başarıyla yürütmek için birçok yöntemi deneyebilirsiniz

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.