60 votes

Quelle est la différence entre les opérateurs "++" et "+= 1 " ?

Dans une boucle en C++, je rencontre généralement des situations où il faut utiliser ++ o +=1 mais je n'arrive pas à faire la différence. Par exemple, si j'ai un entier

int num = 0;

et ensuite, dans une boucle, je fais :

num ++;

o

num += 1;

ils augmentent tous deux la valeur de num Mais quelle est leur différence ? Je doute num++ pourrait travailler plus rapidement que num+=1 mais comment ? Cette différence est-elle suffisamment subtile pour être ignorée ?

0 votes

Vous ne devez pas vous préoccuper de l'implémentation, mais uniquement de la signification de l'expression. La manière dont le compilateur implémente le code sous-jacent n'est pas pertinente et le compilateur choisira la méthode la plus rapide pour implémenter le sens de l'opération (dans ce cas, incrémenter num de 1), qui sera probablement exactement la même pour POD.

1 votes

@DeadMG Le comportement défini a été restauré :D

25 votes

J'ai 63 ans. Que signifie "UB" ?

100voto

Alexandre C. Points 31758

num += 1 est plutôt équivalent à ++num .

Toutes ces expressions ( num += 1 , num++ y ++num ) incrémente la valeur de num d'une unité, mais la valeur de num++ est la valeur num avait antes de il a été incrémenté.

Illustration :

int a = 0;
int b = a++; // now b == 0 and a == 1
int c = ++a; // now c == 2 and a == 2
int d = (a += 1); // now d == 3 and a == 3

Utilisez ce qui vous plaît. Je préfère ++num a num += 1 parce qu'il est plus court.

0 votes

Merci à tous pour votre réponse.

11 votes

Le fait d'être plus petit est certainement un point, mais IMO pas aussi important que le fait que ++a est plus systématiquement généralisable et garantit un fonctionnement efficace, non seulement pour les int mais aussi pour tout type d'itérateur.

6 votes

@leftaroundabout : Les entiers et les itérateurs n'ont rien à voir l'un avec l'autre. Nous ne parlons pas de pointeurs ici (et la généralisation correcte de i += 1 serait std::advance (i, 1) ), et l'OP ne semble pas encore suffisamment informé pour compliquer les choses de la sorte. Je maintiens mon point de vue : la seule différence entre i += 1 y ++i pour les entiers (ce qui est l'objet de la question) est d'ordre cosmétique.

34voto

gokcehan Points 4210

préfixe y postfixe sont des candidats parfaits pour les questions d'examen.

a = 0;
b = a++;  // use the value and then increment --> a: 1, b: 0

a = 0;
b = ++a;  // increment and then use the value --> a: 1, b: 1

+= et sa sœur -= sont des solutions plus générales, principalement destinées à être utilisées avec différents numéros. On pourrait même dire qu'elles sont redondantes lorsqu'elles sont utilisées avec 1 . Lorsqu'il est utilisé avec 1 ils agissent principalement en tant que préfixe opération. En fait, sur ma machine, ils produisent le même code machine. Vous pouvez essayer en utilisant un programme d'exemple tel que :

void foo() {
    int a, b;
    a = 0;

    // use one of these four at a time
    b = a++;          // first case (different)
    b = ++a;          // second case
    b = (a += 1);     // third case
    b = (a = a + 1);  // fourth case
}

int main() {
    foo();
    return 0;
}

et le démontage en gdb ce qui donnerait :

premier cas ( a++ ) (différent)

(gdb) disassemble foo
Dump of assembler code for function foo:
   0x00000000004004b4 <+0>:     push   %rbp
   0x00000000004004b5 <+1>:     mov    %rsp,%rbp
   0x00000000004004b8 <+4>:     movl   $0x0,-0x8(%rbp)
   0x00000000004004bf <+11>:    mov    -0x8(%rbp),%eax
   0x00000000004004c2 <+14>:    mov    %eax,-0x4(%rbp)
   0x00000000004004c5 <+17>:    addl   $0x1,-0x8(%rbp)
   0x00000000004004c9 <+21>:    pop    %rbp
   0x00000000004004ca <+22>:    retq
End of assembler dump.

deuxième cas ( ++a )

(gdb) disassemble foo
Dump of assembler code for function foo:
   0x00000000004004b4 <+0>:     push   %rbp
   0x00000000004004b5 <+1>:     mov    %rsp,%rbp
   0x00000000004004b8 <+4>:     movl   $0x0,-0x8(%rbp)
   0x00000000004004bf <+11>:    addl   $0x1,-0x8(%rbp)
   0x00000000004004c3 <+15>:    mov    -0x8(%rbp),%eax
   0x00000000004004c6 <+18>:    mov    %eax,-0x4(%rbp)
   0x00000000004004c9 <+21>:    pop    %rbp
   0x00000000004004ca <+22>:    retq   
End of assembler dump.

troisième cas ( a += 1 )

(gdb) disassemble foo
Dump of assembler code for function foo:
   0x00000000004004b4 <+0>:     push   %rbp
   0x00000000004004b5 <+1>:     mov    %rsp,%rbp
   0x00000000004004b8 <+4>:     movl   $0x0,-0x8(%rbp)
   0x00000000004004bf <+11>:    addl   $0x1,-0x8(%rbp)
   0x00000000004004c3 <+15>:    mov    -0x8(%rbp),%eax
   0x00000000004004c6 <+18>:    mov    %eax,-0x4(%rbp)
   0x00000000004004c9 <+21>:    pop    %rbp
   0x00000000004004ca <+22>:    retq   
End of assembler dump.

quatrième cas ( a = a + 1 )

(gdb) disassemble foo
Dump of assembler code for function foo:
   0x00000000004004b4 <+0>:     push   %rbp
   0x00000000004004b5 <+1>:     mov    %rsp,%rbp
   0x00000000004004b8 <+4>:     movl   $0x0,-0x8(%rbp)
   0x00000000004004bf <+11>:    addl   $0x1,-0x8(%rbp)
   0x00000000004004c3 <+15>:    mov    -0x8(%rbp),%eax
   0x00000000004004c6 <+18>:    mov    %eax,-0x4(%rbp)
   0x00000000004004c9 <+21>:    pop    %rbp
   0x00000000004004ca <+22>:    retq   
End of assembler dump.

Comme vous pouvez le voir, ils produisent le même code machine même sans que les optimisations du compilateur soient activées, à l'exception du premier cas qui a addl après mov s. Cela signifie que vous devriez utiliser celui que vous aimez en tant qu'utilisateur et laisser les compilateurs faire le reste.

Enfin, notez que les opérateurs cousins *= y /= n'ont pas postfixe y préfixe des contreparties.

13voto

dreamzor Points 2327

Les ++ les opérateurs préfixes ou postfixes changer la valeur de la variable.

int a = 0;
int b = a++; // b is equal to 0, a is equal to 1

Ou préfixe :

int a = 0;
int b = ++a; // b = 1, a = 1

Utilisés de la sorte, ils sont identiques :

int a = 0;
++a; // 1
a++; // 2
a += 1; // 3

2 votes

Pour être clair, a += 1 a également une valeur de retour, mais c'est la valeur de a après l'incrémentation.

2 votes

Re a += 1 a également une valeur de retour : De même = . Cette = renvoie une valeur, c'est ce qui fait que des affirmations telles que a = b = c = 0; valable.

2 votes

Ils n'ont pas de valeur de retour, ils sont expressions et d'évaluer quelque chose.

7voto

Desert Ice Points 1092

Les deux opérateurs augmentent la valeur de n de 1. La différence entre eux existe lorsque vous utilisez les opérateurs avec l'opérateur d'affectation.

Par exemple :

Premier cas --Opérateur post-incrément

int n=5;
int new_var;

new_var=n++;

print("%d",new_var);

Sortie=5

Deuxième cas

int n=5;
n+=1;
new_var=n;
print("%d",new_var);

Sortie =6

Ce résultat est très proche de celui qu'obtiendrait l'opérateur avant incrémentation.

Deuxième cas utilisant l'opérateur de pré-incrémentation

int n=5;

new_var=++n;
print("%d",new_var);

Sortie =6

2 votes

Il existe deux opérateurs ++, le pré-incrément ( ++n ) et après incrémentation ( n++ ). Vous n'avez regardé que la post-incrémentation. Essayez votre comparaison avec le pré-incrément. BTW, la pratique recommandée en C++ est de préférer la pré-incrémentation à la post-incrémentation lorsque l'une ou l'autre fait l'affaire.

2voto

bigfish Points 25

Ils sont généralement identiques et il n'y a pas lieu de clarifier la différence entre eux. Mais la mise en œuvre de ces deux déclarations est en fait différente. Par exemple, a+=1 compilant en assembleur est
ajouter a,1
et a++ ou ++a est
inc a
Il peut y avoir une légère différence d'efficacité parce qu'il s'agit de deux CPU différents.

2 votes

Le compilateur en est également conscient et supprime toute différence lors de l'optimisation.

0 votes

Je suis sûr que le compilateur a beaucoup de problèmes avec cette optimisation. Pour être clair, je suis sarcastique. Il n'y aura aucune différence dans les instructions sous-jacentes utilisées. N'importe quel compilateur écrit au cours des 100 derniers millions d'années peut effectuer cette optimisation, même le cerveau humain.

0 votes

Cela n'est vrai que si l'opérateur de postincrémentation est utilisé isolément. S'il est utilisé à l'intérieur d'une expression plus large, le code généré sera différent car la sémantique est différente. Veuillez consulter la réponse que j'ai fournie pour plus d'informations. Désolé de devoir rétrograder cette réponse, mais elle est incorrecte.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X