L'indexation, l'affectation et l'incrémentation dans une instruction se comportent différemment en C ++ et en C #. Pourquoi?

StackOverflow https://stackoverflow.com/questions/1606407

Question

Pourquoi cet exemple de code qui se comporte différemment dans c ++ et C # .

[Exemple C ++]

int arr[2];
int index = 0;
arr[index] = ++index;

Le résultat sera arr [1] = 1 ;

[Exemple C #]

int[] arr = new int[2];
int index = 0;
arr[index] = ++index;

Le résultat sera arr [0] = 1 ;

Je trouve cela très étrange. Il doit sûrement y avoir une raison pour que les deux langues l'appliquent différemment. Je me demande quelle serait la sortie C ++ / CLI ?

Était-ce utile?

La solution

Comme d'autres l'ont noté, le code de ce code est indéfini en C / C ++. Vous pouvez obtenir n'importe quel résultat.

Le comportement de votre code C # est strictement défini par le standard C #.

  

Il doit sûrement y avoir une raison pour que les deux langues l’implémentent différemment?

Eh bien, supposons que vous conceviez C # et souhaitiez rendre le langage facile à apprendre pour les programmeurs C ++. Souhaitez-vous choisir de copier l'approche de C ++ à ce problème, à savoir, laissez-le indéfini? Voulez-vous vraiment rendre facile aux développeurs parfaitement intelligents l'écriture accidentelle de code que le compilateur ne peut que donner le sens qu'il veut?

Les concepteurs de C # ne croient pas que le comportement non défini d’expressions simples soit une bonne chose et nous avons donc défini de manière stricte la signification de telles expressions. Nous ne pouvons éventuellement pas être d'accord avec ce que fait chaque compilateur C ++, car différents compilateurs C ++ donnent des résultats différents pour ce type de code et nous ne pouvons donc pas être d'accord avec tous.

Quant aux raisons pour lesquelles les concepteurs de C ++ estiment qu’il est préférable de laisser des expressions simples comme celle-ci pour adopter un comportement indéfini, eh bien, vous devrez demander à l’une d’elles. Je pourrais certes formuler certaines conjectures, mais ce ne sont que des suppositions éclairées.

J'ai écrit un certain nombre d'articles de blog sur ce type de problème. Mon dernier en date concernait à peu près exactement le code que vous mentionnez ici. Quelques articles à lire:

Comment la conception de C # encourage l'élimination des bugs subtils:

http: //blogs.msdn.com/ericlippert/archive/2007/08/14/c-and-the-pit-of-des-pair.aspx

Quelle est exactement la relation entre la précédence, l'associativité et l'ordre d'exécution en C #?

http: // blogs.msdn.com/ericlippert/archive/2008/05/23/precedence-vs-associativity-vs-order.aspx

Dans quel ordre se produisent les effets secondaires de l'indexation, de l'affectation et de l'incrément?

http: // blogs. msdn.com/ericlippert/archive/2009/08/10/precedence-vs-order-redux.aspx

Autres conseils

Votre code C ++ peut, en fait, faire n'importe quoi. arr [index] = ++ index; invoque un comportement indéfini.

Le comportement d'utilisation d'index et ++ index dans la même affectation n'est pas spécifié en C ++. Vous ne pouvez simplement pas faire cela: écrivez arr [index] = index + 1 et incrémentez votre variable par la suite. En outre, avec mon compilateur C ++ sur ma machine, je vois arr [0] = 1 et arr [1] n’est pas touché.

Dans le cas de C ++, au moins, vous invoquez un comportement indéfini en préincrémentant et en utilisant index sans point de séquence entre les deux. Si vous transmettez ce code à GCC avec les avertissements activés, il indiquera:

preinc.cpp:6: warning: operation on ‘index’ may be undefined

Je suppose que cela n’est pas non plus défini en C #, mais je ne connais pas le langage. Toutefois, pour le moins possible en C et C ++, la réponse est que le compilateur peut faire tout ce qu’il veut sans se tromper, car votre code est erroné. Différents compilateurs (ou même le même compilateur) ne sont pas tenus de produire des résultats cohérents .

Remarque : conformément à @Eric Lippert réponse , le comportement est strictement défini pour C #, alors laissez-moi reformuler ma réponse à ce sujet.

Ce code:

arr[index] = ++index;

Difficile à lire même si le compilateur C # sait exactement comment l’évaluer et dans quel ordre. Pour cette seule raison, il convient de l'éviter.

La page MSDN sur les opérateurs C # va même jusqu'à préciser que ce comportement pourrait être indéfini, même si Eric souligne que ce n'est pas le cas. Le fait que de multiples sources de documentation (je ferai confiance à Eric sur ce point cependant) rend les choses différentes, est également un signe que cela pourrait être quelque chose de mieux laissé seul.

Le résultat de la version C ++ ne sera pas toujours identique à celui que vous écrivez car vous appelez le comportement non défini . En C ++, vous obtiendrez un comportement non défini si vous utilisez la valeur d'une variable dans une expression lorsque cette variable est également modifiée, à moins que la lecture de cette valeur ne fasse partie de la détermination de la valeur à écrire, ou expression contient un séquence entre la lecture et l’écriture.

Dans votre expression, vous lisez la valeur de index pour déterminer où attribuer le résultat du côté droit du = , mais le sous-menu de droite expression modifie également index .

index en C # est un type de valeur, ce qui signifie que vous retournez une nouvelle instance de la valeur lorsque vous effectuez des opérations dessus.

Si vous l'imaginez comme une procédure plutôt que comme un opérateur, la procédure ressemblerait à ceci:

public int Increment(int value)
{
   int returnValue=value+1;
   return returnValue;
}

C ++, cependant, fonctionne sur la référence de l'objet, la procédure devrait donc ressembler à:

int Increment(int &value)
{
   value=value+1;
   return value;
}

Remarque: si vous appliquiez l'opérateur à un objet (par exemple, l'opérateur ++ surchargé), alors C # se comporterait comme C ++, car les types d'objet sont passés en tant que références.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top