Qu'est-ce que l'opérateur «->» en C ++?


8927

Après avoir lu les fonctions cachées et coins sombres de C ++ / STL sur comp.lang.c++.moderated, j'ai été complètement surpris que le suivant extrait compilé et a travaillé dans Visual Studio 2008 et G ++ 4.4.

Voici le code:

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

Production:

9 8 7 6 5 4 3 2 1 0

Je suppose que c'est C, car cela fonctionne également dans GCC. D'où cela est-il défini dans la norme et d'où vient-il?


503
Ou même juste un bon espacement ... Je ne pense pas avoir jamais vu d'espace entre la variable et l'une ++ou l' autre ou --avant ...
Matthew Scharley

1155
Cet opérateur "va à" peut être inversé (0 <- x). Et il y a aussi un opérateur "run to" (0 <---- x). Décidément, la chose la plus drôle que j'ai jamais entendu parler de la syntaxe c ++ =) +1 pour la question.
SadSido

233
Curieusement, bien que l'interprétation soit très fausse, elle décrit ce que le code fait correctement. :)
Noldorin

811
Imaginez les nouvelles possibilités de syntaxe: #define upto ++<, #define downto -->. Si vous vous sentez mal, vous pouvez le faire #define for while(et #define do ) {(et #define done ;}) et écrire for x downto 0 do printf("%d\n", x) doneOh, l'humanité ...
Chris Lutz

98
Ouvre la possibilité d'une toute nouvelle façon expressive de codage, qui vaut la peine de sacrifier quelques avertissements du compilateur pour: bool CheckNegative (int x) {return x <0? vrai faux ); }
ttt

Réponses:


8606

-->n'est pas un opérateur. Il s'agit en fait de deux opérateurs distincts, --et >.

Le code du conditionnel diminue x, tout en renvoyant xla valeur d'origine (non décrémentée) de, puis compare la valeur d'origine avec l' 0utilisation de l' >opérateur.

Pour mieux comprendre, la déclaration pourrait être rédigée comme suit:

while( (x--) > 0 )

262
Là encore, cela ressemble à une sorte d'opérateur de plage dans ce contexte.
Charles Salvia

109
Dire que x est post-décrémenté puis comparé à 0 revient à dire que x est décrémenté après avoir été comparé à 0
Charles Salvia

8
Je ne pense pas que ce soit pareil. Je pense que le mot "alors" implique qu'il y a un ordre (après décrémentation, la valeur de x est un de moins). Je pense que l'on peut dire "Vous postez décrémenter x puis comparez son ancienne valeur et 0 ..." pour le rendre plus clair. Mais c'est de toute façon un peu marrant. Nous savons tous ce que cela signifie.
Johannes Schaub - litb

38
En Java, il compile également :)
Steven Devijver

44
Son nom, @Jay, est un mauvais style de programmation :-) Ceci est démontré par le fait que la question a été posée en premier lieu. Il est beaucoup plus logique de lier textuellement des opérateurs à la chose sur laquelle ils opèrent plutôt qu'à quelque chose de non lié, ce while (x-- > 0)serait donc plus approprié. Cela rend également plus clair ce qui se passe (au moins dans un éditeur de polices fixes), ce qui signifie que les parenthèses dans cette réponse ne seraient pas nécessaires.
paxdiablo

3132

Ou pour quelque chose de complètement différent ... x glisse vers 0.

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

Pas si mathématique, mais ... chaque image vaut mille mots ...


216
@mafutrct - Si je me souviens bien, \ en C ajoute simplement la ligne suivante comme s'il n'y avait pas de saut de ligne. Les \ s ici ne font rien du tout.
Hogan

2
@mafu le caractère '\' indique au compilateur que la ligne actuelle continue dans la ligne suivante et donc le compilateur doit fusionner les deux lignes et compiler comme une seule. 'while (x -> 0)' s'exécutera jusqu'à ce que x soit égal à -1. Mais, la façon dont il fait les indentations donne l'impression que x glisse à zéro. 'Alors que x glisse à 0 ...'
Felype

16
IIRC, K&R C a permis des espaces entre les 'dans l'opérateur de décrémentation, auquel cas vous pourriez avoir les barres obliques inverses au milieu, ce qui serait encore plus cool. :)
Jules

10
@ArnavBorborah, c'est une ancienne expression why waste words when a picture does a better job, utilisée comme plaisanterie dans ce contexte. (il y a en fait 2 mots while- clés et printf)
non synchronisé

88
Ah oui, l'opérateur de diapositive obscure. Comment pourrai-je oublier!
demonkoryu


1278

C'est équivalent à

while (x-- > 0)

x--(post décrément) est équivalent à x = x-1so, le code se transforme en:

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

15
Ceci n'est pas tout à fait vrai. La valeur de x à l'intérieur du corps de boucle est différente dans le second cas. L'instruction d'affectation dans votre exemple doit être au - dessus de la logique pour qu'elle soit équivalente. Postfix - soustrait 1, mais la comparaison se fera avec la valeur d' avant la soustraction.
uliwitness

4
@uliwitness Ce sont vraiment équivalents. Ce serait faux si le préfixe était utilisé: 0 >-- xdans ce cas, il xest décrémenté avant la logique. En postfixe, la logique est exécutée avant la décrémentation et donc les deux échantillons sont équivalents. N'hésitez pas à les écrire dans un Consoleet à les tester.
Candleshark

12
Ils ne sont toujours pas équivalents. Après la première boucle, x est -1 (ou survolé s'il n'est pas signé), après la seconde, il est 0. (En supposant que x commence non négatif, aucune boucle ne modifie x ou ne se casse ou…)
César

1
while(x=x-1,x+1 > 0)est équivalent.
SS Anne

2
@Shebham, voici un exemple de compteur: si x commence comme 0, sous la boucle d'origine il sortirait comme -1, avec votre version il resterait zéro. Ils ne sont donc pas équivalents.
Elliott

1210

x peut aller à zéro encore plus vite dans la direction opposée:

int x = 10;

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

8 6 4 2

Vous pouvez contrôler la vitesse avec une flèche!

int x = 100;

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

90 80 70 60 50 40 30 20 10

;)


6
quel système d'exploitation, ce type de sortie généré, j'utilise un ubuntu 12.04 en ce que j'avais un message d'erreur
Bhuvanesh

74
Bien que cela doive être évident, pour tous les débutants en C ++, lisez ceci: ne le faites pas. Utilisez simplement l'affectation augmentée si vous devez augmenter / diminuer de plus d'un.
Blimeo

263
Zéro avec des "lasers". tant que (0> - - - - - - - - - - ---------- x) ... même sortie.
Samuel Danielson

4
@phord êtes-vous sûr qu'il ne compile pas? -> coliru.stacked-crooked.com/a/5aa89a65e3a86c98
doc

18
@doc Il compile en c ++, mais pas en c.
phord

549

Ses

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

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

       printf("%d ", x);
     }

     return 0;
}

L'espace juste rend les choses drôles, --diminue et >compare.


432

L'utilisation de -->a une pertinence historique. La décrémentation était (et l'est toujours dans certains cas), plus rapide que l'incrémentation sur l'architecture x86. L'utilisation -->suggère que cela xva 0et fait appel à ceux qui ont des antécédents mathématiques.


479
Pas exactement vrai. La décrémentation et l'incrémentation prennent le même temps, l'avantage de cela est que la comparaison à zéro est très rapide par rapport à la comparaison par rapport à une variable. Cela est vrai pour de nombreuses architectures, pas seulement pour x86. N'importe quoi avec une instruction JZ (saut si zéro). En fouillant, vous pouvez trouver de nombreuses boucles "for" qui sont écrites à l'envers pour enregistrer des cycles sur la comparaison. Ceci est particulièrement rapide sur x86 car l'acte de décrémentation de la variable définit le drapeau zéro de manière appropriée, de sorte que vous pouvez ensuite créer une branche sans avoir à comparer explicitement la variable.
burito

25
Eh bien, décrémenter vers zéro signifie que vous n'avez qu'à comparer avec 0 par itération de boucle, alors qu'itérer vers n signifie comparer avec n chaque itération. Le premier a tendance à être plus facile (et sur certaines architectures, il est automatiquement testé après chaque opération de registre de données).
Joey Adams

9
@burrito Bien que je ne sois pas en désaccord, les boucles conditionnées à des valeurs non nulles sont généralement prédites presque parfaitement.
Duncan

14
L'incrémentation et la décrémentation sont également rapides, probablement sur toutes les plateformes (certainement sur x86). La différence réside dans le test de la condition de fin de boucle. Pour voir si le compteur a atteint zéro est pratiquement gratuit - lorsque vous décrémentez une valeur, un indicateur zéro est défini dans le processeur et pour détecter la condition de fin, il vous suffit de vérifier cet indicateur tandis que lorsque vous incrémentez une opération de comparaison est requise avant la condition de fin peut être détecté.
lego

7
Bien sûr, tout cela est théorique ces jours-ci, car les compilateurs modernes peuvent vectoriser et inverser automatiquement les boucles.
Lambda Fairy


363

Complètement geek, mais je vais utiliser ceci:

#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;
}

17
@SAFX - Ce serait parfaitement hiéroglyphique avec des parenthèses égyptiennes
mouviciel

1
Cela ne compile pas. C n'est pas Pascal, où l'intérieur de do ... whileest une liste d'instructions. En C, c'est un bloc, donc ça doit l'être do { ... } while.
Marquis de Lorne

25
@EJP il compile. La syntaxe est do statement while ( expression ) ;. Cela dit, j'espère qu'il est entendu que je voulais dire l'exemple comme une blague.
Escualo

321

Un livre que j'ai lu (je ne me souviens pas correctement du livre) a déclaré: Les compilateurs essaient d'analyser les expressions sur le plus gros jeton en utilisant la règle de gauche à droite.

Dans ce cas, l'expression:

x-->0

Analyse les plus gros jetons:

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

La même règle s'applique à cette expression:

a-----b

Après l'analyse:

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

J'espère que cela aide à comprendre l'expression compliquée ^^


98
Votre deuxième explication n'est pas correcte. Le compilateur verra a-----bet réfléchira (a--)-- - b, qui ne compile pas car a--ne renvoie pas de valeur l.
Tim Leaf

22
En outre, xet --sont deux jetons distincts.
Roland Illig

23
@DoctorT: il passe le lexer. seul le passage sémantique est capable d'émettre cette erreur. donc son explication est correcte.
v.oddou

9
Tant que vous pensez -->être un opérateur (ce qui implique que la question a été posée), cette réponse n'est pas du tout utile - vous penserez que le jeton 2 l'est -->, pas seulement --. Si vous savez que ce -->n'est pas un opérateur, vous n'avez probablement pas de problème à comprendre le code dans la question, donc, à moins que vous n'ayez une question complètement différente, je ne sais pas vraiment comment cela pourrait être utile.
Bernhard Barker

4
L'exemple @DoctorT peut être correct en supposant que l' aopérateur de post-décrémentation est surchargé, ce qui renvoie lvalue. coliru.stacked-crooked.com/a/e1effc351ae79e9f
doc

275

C'est exactement la même chose que

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

pour les nombres non négatifs


153
Cela ne devrait-il pas être for(--x++;--x;++x--)?
Mateen Ulhaq

9
@DoctorT qui est ce qui unsignedest pour
Cole Johnson

12
@MateenUlhaq, c'est faux selon la norme l'expression --x++a un comportement indéfini selon §1.9.15
WorldSEnder

S'il utilisait unsigned, il aurait utilisé%u
Cacahuete Frito

242

Quoi qu'il en soit, nous avons maintenant un opérateur "va à". "-->"est facile à retenir comme une direction, et "tandis que x va à zéro" est un sens direct.

De plus, il est un peu plus efficace que "for (x = 10; x > 0; x --)"sur certaines plateformes.


17
Va toujours être vrai, surtout lorsque la valeur de x est négative.
Ganesh Gopalasubramanian

15
L'autre version ne fait pas la même chose - avec for (size_t x=10; x-->0; )le corps de la boucle exécuté avec 9,8, .., 0 alors que l'autre version a 10,9, .., 1. Sinon, il est assez difficile de quitter une boucle jusqu'à zéro avec une variable non signée.
Pete Kirkham

4
Je pense que c'est un peu trompeur ... Nous n'avons pas d'opérateur littéralement "va à", car nous avons besoin d'un autre ++>pour faire le travail incrémentiel.
tslmy

19
@Josh: en fait, le débordement donne un comportement indéfini pour int, il pourrait donc tout aussi facilement manger votre chien que de le mettre xà zéro s'il commence au négatif.
SamB

3
C'est un idiome très important pour moi pour la raison donnée dans le comnmet par @PeteKirkham, car j'ai souvent besoin de faire des boucles décroissantes sur des quantités non signées jusqu'à 0. (À titre de comparaison, l'idiome consistant à omettre des tests pour zéro, comme écrire à la while (n--)place pour non signé n, ne vous achète rien et pour moi entrave considérablement la lisibilité.) Il a également la propriété agréable que vous spécifiez un de plus que l'index initial, qui est généralement ce que vous voulez (par exemple, pour une boucle sur un tableau, vous spécifiez sa taille). J'aime aussi -->sans espace, car cela rend l'idiome facile à reconnaître.
Marc van Leeuwen

221

Ce code compare d'abord x et 0, puis décrémente x. (Également dit dans la première réponse: vous post-décrémentez x et comparez ensuite x et 0 avec l' >opérateur.) Voir la sortie de ce code:

9 8 7 6 5 4 3 2 1 0

Nous comparons maintenant d'abord puis décrémentons en voyant 0 dans la sortie.

Si nous voulons d'abord décrémenter puis comparer, utilisez ce code:

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

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

Cette sortie est:

9 8 7 6 5 4 3 2 1

177

Mon compilateur imprimera 9876543210 lorsque j'exécuterai ce code.

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

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

Comme prévu. Le while( x-- > 0 )signifie en fait while( x > 0). Le x--poste diminue x.

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

est une façon différente d'écrire la même chose.

C'est bien que l'original ressemble à "tandis que x passe à 0".


4
Le résultat n'est indéfini que lorsque vous incrémentez / décrémentez la même variable plusieurs fois dans la même instruction. Cela ne s'applique pas à cette situation.
Tim Leaf

13
while( x-- > 0 ) actually means while( x > 0)- Je ne suis pas sûr de ce que vous essayez de dire là-bas, mais la façon dont vous l'avez formulé implique que cela --n'a aucun sens, ce qui est évidemment très faux.
Bernhard Barker

Pour ramener le point de départ de @Dukeling, cette réponse n'est pas la même que la publication d'origine. Dans le message d'origine, ce xsera -1après qu'il quitte la boucle, tandis que dans cette réponse, ce xsera 0.
Mark Lakata

148

Il manque un espace entre --et >. xest post-décrémenté, c'est-à-dire décrémenté après avoir vérifié la condition x>0 ?.


42
L'espace n'est pas manquant - C (++) ignore les espaces blancs.

27
@ H2CO3 Ce n'est pas vrai en général. Il y a des endroits où l'espace blanc doit être utilisé pour séparer les jetons, par exemple dans #define foo()versus #define foo ().
Jens

30
@Jens Et si: "L'espace ne manque pas - C (++) ignore les espaces blancs inutiles."?
Kevin P. Rice

139

--est l' opérateur de décrémentation et >est l' opérateur supérieur à .

Les deux opérateurs sont appliqués comme un seul comme -->.


11
Ils sont appliqués comme les 2 opérateurs distincts qu'ils sont. Ils ne sont écrits que de manière trompeuse pour ressembler à "un seul".
underscore_d

129

C'est une combinaison de deux opérateurs. La première --consiste à décrémenter la valeur et >à vérifier si la valeur est supérieure à l'opérande de droite.

#include<stdio.h>

int main()
{
    int x = 10;

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

    return 0;
}

La sortie sera:

9 8 7 6 5 4 3 2 1 0            

122

En fait, xest post-décrémentation et avec cette condition est en cours de vérification. Ce n'est pas -->, c'est(x--) > 0

Remarque: la valeur de xest modifiée après la vérification de la condition, car elle post-décrémente. Certains cas similaires peuvent également se produire, par exemple:

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

6
Sauf que ++> peut difficilement être utilisé dans un certain temps (). Un opérateur "va jusqu'à ..." serait ++ <, ce qui ne semble pas aussi agréable. L'opérateur -> est une heureuse coïncidence.
Florian F

2
@BenLeggiero Cela pourrait `` fonctionner '' dans le sens de générer du code qui fait quelque chose (tout en exaspérant les lecteurs qui n'aiment pas le code faux-intelligent), mais la sémantique est différente, car son utilisation de la précrément signifie qu'elle exécutera une itération de moins. Comme exemple artificiel, il n'exécuterait jamais le corps de la boucle s'il était xdémarré à 1, mais le while ( (x--) > 0 )ferait. {edit} Eric Lippert a couvert les deux dans ses notes de version C # 4: blogs.msdn.microsoft.com/ericlippert/2010/04/01/…
underscore_d

120

C et C ++ obéissent à la règle du "grignotage maximal". De la même manière que a --- b est traduit en (a--) - b, dans votre cas, se x-->0traduit par (x--)>0.

Ce que la règle dit essentiellement, c'est que, de gauche à droite, les expressions sont formées en prenant le maximum de caractères qui formeront une expression valide.


5
C'est ce que l'OP a supposé: "((a) ->)" était le grignotage maximal. Il s'avère que l'hypothèse originale de l'OP était incorrecte: "->" n'est pas un opérateur valide maximum.
David

4
Aussi connu comme l'analyse gourmande, si je me souviens bien.
Roy Tinker

1
@RoyTinker Balayage gourmand . L'analyseur n'a rien à voir avec cela.
Marquis de Lorne

27

Pourquoi toutes ces complications?

La réponse simple à la question d'origine est juste:

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

Fait la même chose. Je ne dis pas que vous devriez le faire comme ça, mais cela fait la même chose et aurait répondu à la question dans un message.

C'est x--juste un raccourci pour ce qui précède, et >c'est juste un normal supérieur à operator. Pas de grand mystère!

Il y a trop de gens qui compliquent les choses simples de nos jours;)


17
Cette question n'est pas sur les complications, mais sur ** Caractéristiques cachées et coins sombres de C ++ / STL **
pix

20
Le programme donne ici une sortie différente de l'original car x ici est décrémenté après printf. Cela montre bien comment les «réponses simples» sont généralement incorrectes.
Öö Tiib

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

2
Ça ne fait pas la même chose. Déplacez votre x=x-1avant printfalors vous pouvez dire "ça fait la même chose".
CITBL

26

De la manière conventionnelle, nous définirions une condition dans la whileparenthèse de boucle ()et une condition de terminaison à l'intérieur des accolades {}, mais--> définir les deux à la fois.

Par exemple:

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

Cela décrémente aet exécute la boucle tandis que aest supérieur à0 .

Classiquement, ce serait:

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

Dans les deux sens, nous faisons la même chose et atteignons les mêmes objectifs.


5
Ceci est une erreur. Le code de la question fait: 'test-write-execute' (testez d'abord, écrivez une nouvelle valeur, exécutez la boucle), votre exemple est 'test-execute-write'.
v010dya

@ v010dya Correction de la réponse, maintenant c'est test-write-executecomme dans la question, merci de l'avoir signalé!
Kotauskas

@VladislavToncharov Votre modification était toujours erronée. Voir le mien.
SS Anne

8

(x --> 0) veux dire (x-- > 0)

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

  2. vous pouvez utiliser (-- x > 0) c'est méchant(--x > 0)
    output -: 9 8 7 6 5 4 3 2 1

  3. vous pouvez utiliser
(--\
    \
     x > 0)

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

  1. vous pouvez utiliser
(\
  \
   x --> 0)

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

  1. vous pouvez utiliser
(\
  \
   x --> 0
          \
           \
            )

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

  1. vous pouvez également utiliser
(
 x 
  --> 
      0
       )

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

de même, vous pouvez essayer de nombreuses méthodes pour exécuter cette commande avec succès

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.