2010-09-18 18 views
6

Una domanda semplice, ma non ho trovato una risposta definitiva su Stack Overflow.Una struttura C# è mai stata inserita se usata come valore di ritorno di una funzione?

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

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

È un C# struct (tipo di valore) sempre copiati stack quando tornato da una funzione, non importa quanto grande potrebbe essere? Il motivo per cui non sono sicuro è che per alcuni set di istruzioni diversi da MSIL (come x86), un valore di ritorno di solito deve inserirsi in un registro del processore e lo stack non è direttamente coinvolto.

In tal caso, è il sito di chiamata che pre-alloca lo spazio sullo stack CLR per il tipo di valore restituito (previsto)?

[modifica: riassunto delle risposte:] Per l'intento della domanda originale, la risposta è no; il CLR non inserirà mai (silenziosamente) una struttura solo allo scopo di inviarlo come valore di ritorno.

+0

@Brian: grazie, me ne rendo conto, ma penso che tu stia dicendo che il processo di restituirlo dalla funzione stessa non comporta alcuna boxe. Ho aggiornato il codice per rendere la domanda più chiara. –

+0

Grande, grazie per le vostre risposte! –

+0

Se un ritorno di un tipo di valore è mai (il tuo uso di "sempre" sembra implicare che a volte se accade, non è incondizionato), significa che c'è un unboxing implicito quando assegniamo il ritorno a una variabile di tipo valore, e sembra inefficiente. Non so praticamente nulla di MSIL e CLR quindi non posso aiutarti qui. Ad ogni modo, posso sapere che cosa ha spinto la tua domanda? – blizpasta

risposta

6

È un dettaglio di implementazione pesante del compilatore JIT. In generale, se la struttura è abbastanza piccola e ha membri semplici, viene restituita nei registri della CPU. Se diventa troppo grande, il codice chiamante riserva abbastanza spazio nello stack e passa un puntatore a quello spazio come argomento nascosto extra.

Non sarà mai inserito, a meno che il tipo di ritorno del metodo sia oggetto ovviamente.

Fwiw: questo è anche il motivo per cui il debugger non può visualizzare il valore di ritorno della funzione nella finestra di Autos. A volte doloroso. Ma il debugger non ottiene abbastanza metadati dal compilatore JIT per sapere esattamente dove trovare il valore. Modifica: risolto in VS2013.

6

Una struttura viene inserita ogni volta che si desidera trattarla come object, quindi se si chiama Func e si assegna il risultato all'oggetto verrà inserito nella casella.

E.g. facendo

object o = Func(); 

produrrà il seguente IL

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

che dimostra che il valore di ritorno è inscatolato, perché si assegna a un riferimento del tipo object.

Se lo si assegna a una variabile di tipo Foo non è inserito in una casella e pertanto viene copiato e il valore viene archiviato nello stack.

Inoltre, il boxing non sarebbe di grande aiuto in questo caso poiché implicherebbe la creazione di un oggetto per rappresentare il valore della struttura e i valori vengono effettivamente copiati durante l'operazione di box.

+1

Il fatto che il sito di chiamata debba allocare il numero appropriato di byte nello stack è la ragione per cui le linee guida sulla progettazione .NET suggeriscono che 'struct's dovrebbe idealmente essere non più grande di 16 byte. –

+1

@Richard: hai una fonte per queste informazioni? –

+0

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

Problemi correlati