Rappelez-vous que l'affectation se fait de droite à gauche, et qu'elles sont normales expressions. Donc, à partir de la compilateurs point de vue de la ligne
sample1 = sample2 =0;
est le même que
sample1 =(sample2 =0);
qui est le même que
sample2 =0;
sample1 = sample2;
Qui est, sample2 est attribué à zéro, puis sample1 est affectée de la valeur de sample2. Dans la pratique, de même que l'affectation à la fois à zéro, comme vous l'avez deviné.
Il est sans doute intéressant de noter qu'il n'y a pas de séquençage dans cette expression. Ce qui signifie qu'il n'est pas correct de supposer que sample2 est affecté en premier, et que la valeur attribuée à sample1 est littéralement lire de sample2. Plus correctement, sample1 est la valeur attribuée à l' 0 converti à type de sample2. Et la cession de sample1 peut effectivement se produire avant l'affectation à sample2.
Merci pour la réponse, je voudrais éviter de sample1=sample2=0 dans le nom de la lisibilité et de séquençage question, comme l'a souligné AndreyT.
Pour cela, je voudrais ajouter que sample2=0 renvoie une rvalue qui est égal à la valeur attribuée dans sample2. C'est donc une instruction d'affectation et a une valeur de retour, au plus, égal à la valeur assignée. Que la valeur de retour (valeur r) est ce qui est attribué à sample1.
Officiellement, pour les deux variables t et u de type T et U respectivement
T t;
U u;
la cession
t = u = X;
(où X est certaine valeur) est interprété comme
t =(u = X);
et est équivalente à une paire de cessions indépendantes
u = X;
t =(U) X;
Noter que la valeur de X est censé atteindre variable t "comme si" il est passé par la variable u premier, mais il n'y a aucune obligation de littéralement se produire de cette façon. X simplement converties en type de u avant d'être assigné à t. La valeur ne doit pas être attribué à u d'abord et ensuite copié à partir de u à t. Ces deux missions sont en fait pas séquencé et peut se produire dans n'importe quel ordre, ce qui signifie que
t =(U) X;
u = X;
est aussi valable programme d'exécution pour cette expression. (Notez que ce séquençage de la liberté est spécifique au langage C, dans lequel le résultat d'une affectation dans une rvalue. En C++ affectation évalue à une lvalue, qui exige "enchaînés" les travaux à être séquencé.)
Il n'y a aucun moyen de dire si c'est une bonne ou une mauvaise programmation, sans voir plus de contexte. Dans les cas où les deux variables sont étroitement liées (comme x et y coordonnées d'un point), paramètre à une valeur commune à l'aide de "enchaînés" cession est en fait parfaitement bien pratique (je dirais même "pratique recommandée"). Mais lorsque les variables sont complètement étrangers, puis les mélanger dans un seul "enchaînés" cession n'est certainement pas une bonne idée. Surtout si ces variables de différents types, ce qui peut conduire à des conséquences inattendues.
Je crois que la norme précise que l'effet est pas comme si la variable a été écrite à travers d'abord, une distinction qui pourrait être extrêmement important si la variable en question est volatile.
Je pense qu'il n'y a pas de bonne réponse sur le langage C sans réel assemblée liste 🙂
Donc pour un simpliste programme:
int main(){int a, b, c, d;
a = b = c = d =0;return a;}
J'ai ce assemly (Kubuntu, gcc 4.8.2, x86_64) avec -O0 option de cours 😉
main:
pushq %rbp
movq %rsp,%rbp
movl $0,-16(%rbp); d =0
movl -16(%rbp),%eax ;
movl %eax,-12(%rbp); c = d
movl -12(%rbp),%eax ;
movl %eax,-8(%rbp); b = c
movl -8(%rbp),%eax ;
movl %eax,-4(%rbp); a = b
movl -4(%rbp),%eax ;
popq %rbp
ret ;return%eax, ie. a
Si gcc est fait le chaînage de toutes les choses.
Un compilateur est libre de faire tout le code de la transformation, qui ne change pas les comportements observables. Par conséquent, l'assemblée ne prouve rien en général. La seule chose que vous pouvez compter sur le c++ standard cahier des charges (si le compilateur s'engage à respecter la norme).
Vous pouvez vous-même décider que cette façon de coder qui est bon ou mauvais.
Simplement voir le code assembleur pour les lignes suivantes dans votre IDE.
Modifiez le code à deux affectations, et de voir les différences.
En plus de cela, vous pouvez également essayer de désactiver/sur des optimisations (Taille & Optimisations de la Vitesse) dans votre compilateur pour voir comment cela affecte le code assembleur.
Les résultats sont les mêmes. Certaines personnes préfèrent le chaînage des affectations s'ils sont tous à la même valeur. Il n'y a rien de mal avec cette approche. Personnellement, je trouve cela préférable si les variables sont étroitement liées l'une des significations.
certains compilateurs va produire un assemblage légèrement plus rapide en comparaison de 2 missions:
sample1 =0;
sample2 =0;
spécialement si vous êtes initialiser à une valeur non nulle. Parce que, l'affectation multiple se traduit par:
sample2 =0;
sample1 = sample2;
Donc au lieu de 2 initialisations vous n'avez qu'à une et une seule copie. La vitesse (le cas échéant) sera minuscule, mais dans des cas intégré chaque petit geste compte!
Je doute qu'il ait jamais existé un compilateur qui a généré différentes en code machine pour sample2=0; sample1=sample2; et sample1=sample2=0;
J'ai été de comparer l'affectation multiple sampl1=sample2=0; contre 2 lits simples: sample1=0; sample2=0; Alors, je crois, il y a une différence, qu'en pensez-vous?
Je doute qu'il y aura une différence. Si il y est, alors sample1=0; sample2=0; est la version plus rapide (de 1 graduation de l'UC ou alors...).
Comme d'autres l'ont dit, l'ordre dans lequel cela est exécuté est déterministe. Le la priorité de l'opérateur de l' = opérateur garantit que cela s'effectue de droite à gauche. En d'autres termes, il garantit que sample2 est donné une valeur avant de sample1.
Cependant, des missions multiples sur une ligne est une mauvaise pratique et interdit par de nombreuses normes de codage (*). Tout d'abord, il n'est pas très lisible (ou vous ne seriez pas poser cette question). Deuxièmement, il est dangereux. Si nous avons par exemple
sample1 = func()+(sample2 = func());
alors la priorité de l'opérateur garantit le même ordre d'exécution comme avant (+ a une priorité plus élevée que =, donc la parenthèse). sample2 obtiendrez d'attribuer une valeur avant de sample1. Mais à la différence de la priorité de l'opérateur, le ordre d'évaluation des opérateurs n'est pas déterministe, c'est un comportement non spécifié. On ne peut pas savoir que le plus à droite de l'appel de fonction est évaluée avant la gauche la plus à un.
Le compilateur est libre de traduire le dessus de la machine de code comme ceci:
Si le code dépend de func() se exécutées dans un ordre particulier, puis nous avons créé un méchant bug. Il peut fonctionner correctement dans un seul endroit du programme, mais de briser dans une autre partie du même programme, même si le code est identique. Parce que le compilateur est libre d'évaluer les sous-expressions dans n'importe quel ordre il aime.
(*) MISRA-C:2004 12.2, MISRA-C:2012 13.4, le CERT-C EXP10-C.
Les appels de fonction est un type d'effets secondaires qui pourraient causer des problèmes. variables, par exemple des registres matériels, auront le même problème que décrit ici.
Le compilateur ne peut pas générer de trois appels à func() pour sample1 = func() + (sample2 = func());.
Prendre soin de ce cas particulier ...
supposons que b est un tableau d'une structure de la forme
{int foo;}
et laissez-je avoir un décalage dans b. Considérons la fonction realloc_b() retournant un int et l'exécution de la redistribution de la matrice b. Considérer cette affectation multiple:
a = (b + i)->foo = realloc_b();
À mon expérience (b + i) est résolu tout d'abord, permettez-nous de le dire, il est b_i dans la RAM ; puis realloc_b() est exécutée. Comme realloc_b() modifie b dans la mémoire RAM, il en résulte que b_i n'est plus attribué.
Variable d'un bien affecté, mais (b + i)->foo n'est pas parce que b a été changé
pourraient résulter de l'exécution de la durée de l'affectation, c'est à dire realloc_b()
Cela peut provoquer une erreur de segmentation depuis b_i est potentiellement en non alloué RAM emplacement.
Être exempt de bugs, et d'avoir (b + i)->foo égal à un, l'un de ligne de commande doit être divisé en deux affectations:
Rappelez-vous que l'affectation se fait de droite à gauche, et qu'elles sont normales expressions. Donc, à partir de la compilateurs point de vue de la ligne
est le même que
qui est le même que
Qui est,
sample2
est attribué à zéro, puissample1
est affectée de la valeur desample2
. Dans la pratique, de même que l'affectation à la fois à zéro, comme vous l'avez deviné.sample2
est affecté en premier, et que la valeur attribuée àsample1
est littéralement lire desample2
. Plus correctement,sample1
est la valeur attribuée à l'0
converti à type desample2
. Et la cession desample1
peut effectivement se produire avant l'affectation àsample2
.sample2=0
renvoie une rvalue qui est égal à la valeur attribuée danssample2
. C'est donc une instruction d'affectation et a une valeur de retour, au plus, égal à la valeur assignée. Que la valeur de retour (valeur r) est ce qui est attribué àsample1
.Officiellement, pour les deux variables
t
etu
de typeT
etU
respectivementla cession
(où
X
est certaine valeur) est interprété commeet est équivalente à une paire de cessions indépendantes
Noter que la valeur de
X
est censé atteindre variablet
"comme si" il est passé par la variableu
premier, mais il n'y a aucune obligation de littéralement se produire de cette façon.X
simplement converties en type deu
avant d'être assigné àt
. La valeur ne doit pas être attribué àu
d'abord et ensuite copié à partir deu
àt
. Ces deux missions sont en fait pas séquencé et peut se produire dans n'importe quel ordre, ce qui signifie queest aussi valable programme d'exécution pour cette expression. (Notez que ce séquençage de la liberté est spécifique au langage C, dans lequel le résultat d'une affectation dans une rvalue. En C++ affectation évalue à une lvalue, qui exige "enchaînés" les travaux à être séquencé.)
Il n'y a aucun moyen de dire si c'est une bonne ou une mauvaise programmation, sans voir plus de contexte. Dans les cas où les deux variables sont étroitement liées (comme
x
ety
coordonnées d'un point), paramètre à une valeur commune à l'aide de "enchaînés" cession est en fait parfaitement bien pratique (je dirais même "pratique recommandée"). Mais lorsque les variables sont complètement étrangers, puis les mélanger dans un seul "enchaînés" cession n'est certainement pas une bonne idée. Surtout si ces variables de différents types, ce qui peut conduire à des conséquences inattendues.volatile
.Je pense qu'il n'y a pas de bonne réponse sur le langage C sans réel assemblée liste 🙂
Donc pour un simpliste programme:
J'ai ce assemly (Kubuntu, gcc 4.8.2, x86_64) avec
-O0
option de cours 😉Si gcc est fait le chaînage de toutes les choses.
Vous pouvez vous-même décider que cette façon de coder qui est bon ou mauvais.
Simplement voir le code assembleur pour les lignes suivantes dans votre IDE.
Modifiez le code à deux affectations, et de voir les différences.
En plus de cela, vous pouvez également essayer de désactiver/sur des optimisations (Taille & Optimisations de la Vitesse) dans votre compilateur pour voir comment cela affecte le code assembleur.
Les résultats sont les mêmes. Certaines personnes préfèrent le chaînage des affectations s'ils sont tous à la même valeur. Il n'y a rien de mal avec cette approche. Personnellement, je trouve cela préférable si les variables sont étroitement liées l'une des significations.
signifie
si et seulement si
sample2
est déclarée auparavant.Vous ne pouvez pas le faire de cette façon:
Concernant le style de codage et de diverses recommandations relatives au codage, voir ici:
La lisibilité a=b=c ou a=c; b=c;?
Je crois qu'en utilisant
certains compilateurs va produire un assemblage légèrement plus rapide en comparaison de 2 missions:
spécialement si vous êtes initialiser à une valeur non nulle. Parce que, l'affectation multiple se traduit par:
Donc au lieu de 2 initialisations vous n'avez qu'à une et une seule copie. La vitesse (le cas échéant) sera minuscule, mais dans des cas intégré chaque petit geste compte!
sample2=0; sample1=sample2;
etsample1=sample2=0;
sample1=0; sample2=0;
est la version plus rapide (de 1 graduation de l'UC ou alors...).Comme d'autres l'ont dit, l'ordre dans lequel cela est exécuté est déterministe. Le la priorité de l'opérateur de l' = opérateur garantit que cela s'effectue de droite à gauche. En d'autres termes, il garantit que sample2 est donné une valeur avant de sample1.
Cependant, des missions multiples sur une ligne est une mauvaise pratique et interdit par de nombreuses normes de codage (*). Tout d'abord, il n'est pas très lisible (ou vous ne seriez pas poser cette question). Deuxièmement, il est dangereux. Si nous avons par exemple
alors la priorité de l'opérateur garantit le même ordre d'exécution comme avant (+ a une priorité plus élevée que =, donc la parenthèse). sample2 obtiendrez d'attribuer une valeur avant de sample1. Mais à la différence de la priorité de l'opérateur, le ordre d'évaluation des opérateurs n'est pas déterministe, c'est un comportement non spécifié. On ne peut pas savoir que le plus à droite de l'appel de fonction est évaluée avant la gauche la plus à un.
Le compilateur est libre de traduire le dessus de la machine de code comme ceci:
Si le code dépend de func() se exécutées dans un ordre particulier, puis nous avons créé un méchant bug. Il peut fonctionner correctement dans un seul endroit du programme, mais de briser dans une autre partie du même programme, même si le code est identique. Parce que le compilateur est libre d'évaluer les sous-expressions dans n'importe quel ordre il aime.
(*) MISRA-C:2004 12.2, MISRA-C:2012 13.4, le CERT-C EXP10-C.
sample1 = func() + (sample2 = func());
.Prendre soin de ce cas particulier ...
supposons que b est un tableau d'une structure de la forme
et laissez-je avoir un décalage dans b. Considérons la fonction realloc_b() retournant un int et l'exécution de la redistribution de la matrice b. Considérer cette affectation multiple:
a = (b + i)->foo = realloc_b();
À mon expérience (b + i) est résolu tout d'abord, permettez-nous de le dire, il est b_i dans la RAM ; puis realloc_b() est exécutée. Comme realloc_b() modifie b dans la mémoire RAM, il en résulte que b_i n'est plus attribué.
Variable d'un bien affecté, mais (b + i)->foo n'est pas parce que b a été changé
pourraient résulter de l'exécution de la durée de l'affectation, c'est à dire realloc_b()
Cela peut provoquer une erreur de segmentation depuis b_i est potentiellement en non alloué RAM emplacement.
Être exempt de bugs, et d'avoir (b + i)->foo égal à un, l'un de ligne de commande doit être divisé en deux affectations: