指向非托管代码的int指针

本文关键字:int 指针 非托管代码 | 更新日期: 2023-09-27 18:09:10

我是c#新手,有一个简单的问题。从非托管代码中,我收到一个int指针:

public foo(ref IntPtr state)
{
   _myState = state;
}

_myState是该类的IntPtr成员。现在我想通过_myState与非托管c++代码交换状态。如果我这样写,一切正常:

public foo(ref IntPtr state)
{
   _myState = state;
   ....do some stuff
   state = 7;
}

在非托管应用程序中,我可以看到新值7。但是如果我这样写:

public foo(ref IntPtr state)
{
   _myState = state;
   ...do some stuff
   _myState = 7;
}

则什么也没发生。state的初始值是0,当将myState更改为7时,它在非托管应用程序中不会更新。我怎么能分配一个成员变量像_myState的状态参数作为一个"指针",所以当状态更新,_myState也更新?在c++中,这对于指针来说是没有问题的…

好的,下面是实际代码:

[DllExport("QFX_InitializeInterfaceObject", CallingConvention = CallingConvention.StdCall)]
    public static void QFX_InitializeInterfaceObject(
        long windowHandle,
        ref IntPtr processState)
    {
        ChartWindowHandle = (IntPtr)windowHandle;
        OrderCommandProcessState = processState;
    }

我想要的是OrderCommandProcessState得到与processState相同的引用到它的值

指向非托管代码的int指针

首先,我要确保这一点是清楚的:IntPtr只是一个整数,恰好与该机器体系结构上的本机指针大小相同——例如,它是x64系统上的64位整数。它不一定具有指针的语义,尽管互操作代码将指针塞进IntPtrs中作为安全编组它们的一种方式是常见的。

继续你的具体问题,让我们忽略它是IntPtr这一事实。假设它只是一个int型,因为它基本上就是int型:

public void Foo(ref int x) // x is an alias to another variable of type int.
{
    int y = x; // y is a copy of the contents of x
    y = 7; // The contents of y are no longer a copy of the contents of x
}

改变y不会改变x;X是另一个变量的别名,y只是该变量内容的副本。它不是同一变量的别名。

如何使一个变量成为另一个变量的别名,以便当一个变量的状态更新时,链接的变量也被更新?在c++中,这对于指针来说是没有问题的。

今天在安全子集中,您只能通过方法的"ref"answers"out"参数来这样做。"ref"形参成为给定变量的别名。这是唯一安全的方法,你可以直接把一个变量作为另一个变量的别名。

CLR也支持ref locals。我们可以实现这样一个功能,事实上我已经用c#创建了原型。在我的原型中,你可以说:

public void Foo(ref int x) // x is an alias to another variable of type int.
{
    ref int y = ref x; // y is now an alias to the same variable that x aliases!
    y = 7; // changing y now changes x, and whatever x 
           // aliases, because those are all the same variable
}

但是我们还没有在c#中添加这个特性,而且近期也没有这样做的计划。如果你有一个令人信服的使用案例,我很乐意听到。(更新:该特性已添加到c# 7中。)

(CLR也允许"ref"返回类型。但是,CLR不允许为变量创建别名,然后将别名存储在字段中!字段的生命周期可能比链接变量的生命周期长,CLR设计者希望避免C和c++所面临的这类bug。

如果你知道变量被固定在内存中的特定位置,那么你可以关闭安全系统并创建一个指向该变量的指针;然后你就有了一个非常普通的指针,你可以像在c++中那样使用它。(也就是说,如果指针ptr指向一个变量,那么*ptr就是该变量的别名。)

unsafe public void Foo(int* x) // *x is an alias to a variable of type int.
{
    int* y = x; // *y is now an alias to the same variable that *x aliases
    *y = 7; // changing *y now changes *x, and whatever *x 
            // aliases, because those are all the same variable
}

CLR对指针的使用没有限制;如果需要,您可以自由地将它们存储在字段中。然而,如果您关闭安全系统,那么负责确保垃圾收集器(或任何拥有该存储的内存管理器——它可能不是托管内存)在指针的生命周期内不会更改别名变量的位置。不要关闭安全系统,除非你真的知道你在做什么;那个安全系统是用来保护你的。