2010-09-18 24 views
6

Une question simple, mais je n'ai pas trouvé de réponse définitive sur Stack Overflow.Une structure C# est-elle jamais encadrée lorsqu'elle est utilisée comme valeur de retour d'une fonction?

struct foo { int x; int y; int z; } 

    foo Func() 
    { 
     return new foo(); 
    } 
    void Func2() 
    { 
     foo f = Func();  // did boxing and unboxing occur? 
    } 

Est-ce une struct C# (type de valeur) toujours copiés à la pile lors du retour d'une fonction, peu importe la taille, il pourrait être? La raison pour laquelle je ne suis pas sûr est que pour certains jeux d'instructions autres que MSIL (tels que x86), une valeur de retour doit généralement entrer dans un registre de processeur, et la pile n'est pas directement impliquée.

Si oui, est-ce le site d'appel qui pré-alloue de l'espace sur la pile CLR pour le type de retour de valeur (attendue)?

[modifier: résumé des réponses:] Pour l'intention de la question initiale, la réponse est non; le CLR ne placera jamais (silencieusement) une structure juste dans le but de l'envoyer comme valeur de retour.

+0

@Brian: merci, je le sais, mais je pense que vous dites que le processus de retour de la fonction elle-même n'implique aucune boxe. J'ai mis à jour le code pour clarifier la question. –

+0

Super, merci pour vos réponses! –

+0

Si un retour d'un type de valeur est toujours (votre utilisation de 'ever' semble impliquer que parfois, si cela arrive, ce n'est pas inconditionnel), cela signifie qu'il y a unboxing implicite lorsque nous assignons le retour à une variable de type valeur, et cela semble inefficace. Je ne sais pas grand-chose sur MSIL et CLR donc je ne peux pas vous aider ici. Quoi qu'il en soit, puis-je savoir ce qui a motivé votre question? – blizpasta

Répondre

6

Il s'agit d'un détail d'implémentation lourd du compilateur JIT. En général, si la structure est assez petite et a des membres simples, elle est renvoyée dans les registres du processeur. S'il devient trop grand, le code appelant réserve suffisamment d'espace sur la pile et passe un pointeur vers cet espace en tant qu'argument caché supplémentaire.

Il ne sera jamais encadré, à moins que le type de retour de la méthode soit objet bien sûr. Fwiw: c'est aussi la raison pour laquelle le débogueur ne peut pas afficher la valeur de retour de la fonction dans la fenêtre Autos. Douloureux parfois. Mais le débogueur ne reçoit pas assez de métadonnées du compilateur JIT pour savoir exactement où trouver la valeur. Edit: corrigé dans VS2013.

6

Une structure est encadrée chaque fois que vous voulez la traiter comme object, donc si vous appelez Func et que vous affectez le résultat à l'objet, il sera encadré.

E.g. faisant

object o = Func(); 

donnera les éléments suivants IL

L_0000: call valuetype TestApp.foo TestApp.Program::Func() 
L_0005: box TestApp.foo 
L_000a: stloc.0 

qui montre que la valeur de retour est encaissée, parce que nous attribuons à une référence du type object.

Si vous l'attribuez à une variable de type Foo, elle n'est pas encadrée et est donc copiée et la valeur est stockée dans la pile.

Aussi, la boxe ne vous aiderait pas vraiment ici car cela impliquerait de créer un objet pour représenter la valeur de la structure, et les valeurs sont effectivement copiées pendant l'opération de boxe.

+1

Le fait que le site d'appel doit allouer le nombre d'octets approprié sur la pile est la raison pour laquelle les directives de conception .NET suggèrent que 'struct's ne devrait idéalement pas dépasser 16 octets. –

+1

@Richard: Avez-vous une source pour cette information? –

+0

Extrayez http://msdn.microsoft.com/en-us/library/y23b5415(VS.71).aspx –