簡體   English   中英

在不使用其返回值的情況下調用非void函數。究竟發生了什么?

[英]Calling a non-void function without using its return value. What actually happens?

所以,我在這里找到了一個類似的問題,但答案更多的是關於風格以及你是否能夠做到這一點。

我的問題是,當你調用一個返回一個對象的非void函數時,實際發生了什么,但是你從不分配或使用所述返回的對象? 所以,更少關於你是否可以,因為我完全知道你可以理解上面鏈接的另一個問題......編譯器/運行時環境有什么作用?

這不是特定於語言的問題,但如果您回答,請說明您所指的語言,因為行為會有所不同。

我相信對於C#和Java,結果都會在堆棧上結束,然后編譯器強制使用pop指令來忽略它。 Eric Lippert關於“The void is invariant”的博客文章提供了更多相關信息。

例如,請考慮以下C#代碼:

using System;

public class Test 
{
    static int Foo() { return 10; }

    public static void Main()
    {
        Foo();
        Foo();
    }
}

Main方法生成的IL(通過MS C#4編譯器)是:

.method public hidebysig static void Main() cil managed
{
    .entrypoint
    .maxstack 8
    L_0000: call int32 Test::Foo()
    L_0005: pop 
    L_0006: call int32 Test::Foo()
    L_000b: pop 
    L_000c: ret 
}

注意pop的調用 - 如果你使Foo成為void方法,它就會消失。

編譯器做了什么?

編譯器生成一個pop指令,丟棄虛擬堆棧的結果。

運行時環境有什么作用?

它通常將代碼嵌入到代碼中,該代碼將返回值傳遞回寄存器,而不是堆棧位置。 (通常是x86體系結構上的EAX。)

抖動知道該值將不被使用,因此它可能生成清除寄存器的代碼。 或許它只是讓它在寄存器中閑置一段時間。

您關心哪個運行時環境? 他們有很多,他們都有不同的緊張情緒。

它取決於所使用的調用約定。 對於小型/簡單類型,返回通常發生在寄存器中。 在這種情況下,函數會將值寫入寄存器,但沒有其他任何內容會引起注意,下次需要該寄存器時(通常會很快發生),它將被其他東西覆蓋。

對於較大的類型,編譯器通常會分配一個結構來保存返回值。 究竟在哪里/如何進行分配會因編譯器而異 - 在某些情況下它將是一個靜態結構,下次調用返回相同類型的函數時,內容將被忽略並被覆蓋。 在其他情況下,它將在堆棧上,即使你沒有使用它,它仍然需要在調用函數之前分配,然后釋放

在.NET中,如果返回的對象是引用類型,並且應用程序沒有對該對象的其他引用,那么在垃圾收集器決定收集它之前,您仍然會在內存中浮動一個對象。

如果返回的對象碰巧持有資源,這可能會很糟糕。 如果它實現了IDisposable接口,那么你的代碼應該在它上面調用Dispose方法,但在這種情況下,永遠不會調用Dispose方法。

編輯:糾正錯字。

對於C ++,通常,編譯器將優化輸出的返回,將其轉換為void函數,如果這允許進一步優化,編譯器可以優化整個函數調用或僅與返回值有關的部分函數調用。 對於Java和C#,我不知道。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM