简体   繁体   English

out 和 int* c# 有什么区别

[英]What's the differences between out and int* c#

As far as I read sending out keyword in c#, will change the parameter.据我阅读c#中的发送关键字,将更改参数。 So what's the different between those two cases:那么这两种情况有什么不同:

  1. using out:用完:

     helper(out param){...} func(){ int param = 0; helper(out param)}
  2. using pointer:使用指针:

     helper(int* param){..} func(){ int param = 0; helper(&param)}

Are they same?他们是一样的吗? Tnx.肿瘤坏死因子。

On the higher level of course there are differences related to how unsafe code is implemented, such that you can only take pointers to primitive types vs. with the out keyword any type can be specified as an argument.当然,在更高级别上, unsafe代码的实现方式存在差异,例如,您只能将指针指向原始类型,而使用out关键字可以将任何类型指定为参数。

But it is interesting to see how the two differ down in the lower level assembly code.但有趣的是,这两者在较低级别的汇编代码中有何不同。

Consider the minimum skeleton code.考虑最小的骨架代码。

static class Program
{
    static unsafe void Main(string[] args)
    {
        int x;
        SetArg(out x);
        Console.WriteLine(x);

        int y;
        SetArg(&y);
        Console.WriteLine(y);
    }

    static void SetArg(out int x)
    {
        x = 10;
    }

    static unsafe void SetArg(int* ptr)
    {
        *ptr = 10;
    }
}

and the resulting assembly code which is inlined以及生成的内联汇编代码

            SetArg(out x);
00007FFD4EB80890  int         3  
00007FFD4EB80891  sub         esp,28h  
00007FFD4EB80894  xor         eax,eax  
00007FFD4EB80896  mov         dword ptr [rsp+24h],eax  
            Console.WriteLine(x);
00007FFD4EB8089A  mov         ecx,0Ah                           ! case a)
00007FFD4EB8089F  call        00007FFDAA4E2890  

            int y;
            SetArg(&y);
00007FFD4EB808A4  lea         rcx,[rsp+24h]  
00007FFD4EB808A9  mov         dword ptr [rcx],0Ah               ! case b)
            Console.WriteLine(y);
00007FFD4EB808AF  mov         ecx,dword ptr [rsp+24h]  
00007FFD4EB808B3  call        00007FFDAA4E2890  
00007FFD4EB808B8  nop  
00007FFD4EB808B9  add         rsp,28h  
00007FFD4EB808BD  ret  

In the first case with the out statement, the value 10 = 0Ah is written directly to a register ecx before being written to the console by the Writeline() function.在使用out语句的第一种情况下,值10 = 0Ah在通过Writeline() function 写入控制台之前直接写入寄存器ecx This is super optimized as no memory is utilized in this operation.这是超级优化的,因为在此操作中没有使用 memory。 This is why it is not recommended to micro optimize your code, and just convey intent with the ref/out keywords and let the compiler do its job.这就是为什么建议对您的代码进行微优化,而只使用ref/out关键字传达意图并让编译器完成其工作的原因。

In the second case with the int* argument, the value 10 = 0Ah is written to a memory address on the stack corresponding to the function argument and then loaded up to ecx from that address before calling Writeline() .在带有int*参数的第二种情况下,值10 = 0Ah被写入堆栈上与 function 参数对应的 memory 地址,然后在调用Writeline()之前从该地址加载到ecx Here the code is not only unsafe but also less optimized as the programmer forced the compiler to store the intermediate value in the stack before usage.这里的代码不仅不安全,而且优化程度较低,因为程序员强制编译器在使用前将中间值存储在堆栈中。

Note than an alternate definition of SetArg() is请注意, SetArg()的替代定义是

    static unsafe void SetArg(int* ptr)
    {
        ptr[0] = 10;  // same as ptr* = 10
    }

but this highlights another potential problem.但这凸显了另一个潜在问题。 Buffer overrun, or out of bounds memory access, because if you had written缓冲区溢出,或超出范围 memory 访问,因为如果你写

ptr[-1] = 10;

or anything else other than ptr[0] which is the intended memory location, then you have corrupted the process memory causing havok.或除ptr[0]之外的任何其他东西,这是预期的 memory 位置,那么您已经破坏了导致破坏的进程 memory。

These two things are conceptually similar.这两件事在概念上是相似的。 The key difference here is:这里的主要区别是:

  • int* is an unmanaged pointer int*是一个非托管指针
  • ref int is a managed pointer ref int是托管指针
  • out int is really just ref int with some extra compiler guard rails around definite assignment out int实际上只是ref int在明确分配周围有一些额外的编译器护栏

So: what is the difference between a managed and unmanaged pointer?那么:托管指针和非托管指针有什么区别? The key differences:主要区别:

  • the GC can correctly track managed pointers GC 可以正确跟踪托管指针
  • which means you don't need to pin/fix some things before you can use them这意味着您无需固定/修复某些东西就可以使用它们
  • and therefore you don't need to use unsafe因此你不需要使用unsafe
  • and it is more verifiable而且更可验证
  • and more people understand the code让更多人看懂代码

Conversely:反过来:

  • you can store an unmanaged pointer in a field on a type (managed pointers can only be held on the stack)您可以将非托管指针存储在类型的字段中(托管指针只能保存在堆栈上)
  • but if that unmanaged pointer talks to something that has moved/gone away: BOOM但是如果那个非托管指针与已经移动/消失的东西对话:BOOM

So: in any scenario where you can use a managed pointer ( ref or out ), in place of an unamnaged pointer: you should .所以:在任何可以使用托管指针( refout )代替未管理指针的情况下:你应该. Honestly, very few C# developers fully understand the nuances of managed pointers, but even fewer fully understand the nuances of unamnaged pointers.老实说,很少有 C# 开发人员完全理解托管指针的细微差别,但完全理解未管理指针的细微差别的就更少了。

The use cases are not same as the keywords name suggests.用例与关键字名称所暗示的不同。

The out is a keyword in C# which is used for the passing the arguments to methods as a reference type. out 是 C# 中的一个关键字,用于将 arguments 作为引用类型传递给方法。 It is generally used when a method returns multiple values.它通常在方法返回多个值时使用。 The out parameter does not pass the property. out 参数不传递属性。

The pointer in C# which is used for the passing the arguments by a reference. C# 中的指针,用于通过引用传递 arguments。 Or we can say that if any changes made in this argument in the method will pointer reflect in that variable when the control return to the calling method.或者我们可以说,如果方法中此参数的任何更改将在控件返回调用方法时将指针反映在该变量中。

Pointers are typically there to interop with C++ and aren't to be used in day to day C# coding.指针通常用于与 C++ 互操作,并且不用于日常 C# 编码。 We can use ref type.我们可以使用 ref 类型。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM