Pointers IntPtr vs C++;指针

Pointers IntPtr vs C++;指针,pointers,c++-cli,Pointers,C++ Cli,我想答案会很简短,比如是或否,所以我一次有两个问题 问题> 1 :我阅读了关于ItpTR的理论解释,但与本地C++指针相比,它更容易理解。假设我有一些结构 ref struct CData { double Key; }; 使用本机代码中的指针,我可以: 1) int address = & CData; // if i need its address 2) double value = * CData; // if i need value of its field 3)

我想答案会很简短,比如是或否,所以我一次有两个问题

<强>问题> 1 :我阅读了关于ItpTR的理论解释,但与本地C++指针相比,它更容易理解。假设我有一些结构

ref struct CData
{
    double Key;
};
使用本机代码中的指针,我可以:

1) int address = & CData; // if i need its address
2) double value = * CData; // if i need value of its field
3) void * pointer1 = CData; // if i want create pointer to struct
4) CData * pointer2 = CData; // if i want create pointer to struct
如果CData是托管对象,则可以通过以下方式执行上述操作:

1) IntPtr address = GCHandle::Alloc(CData).AddrOfPinnedObject() // if i need address
2) cannot get one field within pointer, only direct access within CData.Key
3) IntPtr pointer = GCHandle::ToIntPtr(GCHandle::Alloc(CData)) // if i need pointer
4) the same as # 3
关于本机代码和托管代码中指针之间的相似性,我的建议正确吗

问题#2:在我的原生应用程序中,我没有像void*这样的类型,我能简单地使用int


此处提供的可用数据类型的完整列表-哪种类型可以有效替换void*以便我可以将其与IntPtr结合使用?

IntPtr
不是指针。它是一个大到足以存储指针的整数,就像标准C和C++中的<>代码> uTunpTrtt>/COD>。 在C++/CLI中,“指向托管对象的指针”类型是
interior_ptr
pin_ptr
伪模板。与c#固定块一样,
pin#ptr
将对象固定在托管堆上,允许您将指针作为普通本机指针传递给现有代码,而无需将对象从该代码下移出

很少有任何理由直接在C++/CLI中使用
GCHandle
。改用
pin_ptr
gcroot
模板。有很好的理由避免它,您在问题的一行代码中犯了两个严重错误:

你把把手漏了。您在非固定GCHandle上调用了
addrofpindedobject


使用为此目的而构建的C++/CLI工具。他们会引导你远离这些错误。

IntPtr
不是指针。它是一个大到足以存储指针的整数,就像标准C和C++中的<>代码> uTunpTrtt>/COD>。 在C++/CLI中,“指向托管对象的指针”类型是
interior_ptr
pin_ptr
伪模板。与c#固定块一样,
pin#ptr
将对象固定在托管堆上,允许您将指针作为普通本机指针传递给现有代码,而无需将对象从该代码下移出

很少有任何理由直接在C++/CLI中使用
GCHandle
。改用
pin_ptr
gcroot
模板。有很好的理由避免它,您在问题的一行代码中犯了两个严重错误:

你把把手漏了。您在非固定GCHandle上调用了
addrofpindedobject


使用为此目的而构建的C++/CLI工具。他们会引导你远离这些错误。

似乎我找到了帮助我理解如何使用IntPtr的解释

以下段落包含错误的建议。

  • 我问什么是IntPtr是因为:我需要移动我所有的 C#library(DLL)的有用函数,同时能够 从非托管程序(如Metatrader)调用它们。不幸的是, Metatrader根本不支持指针,所以我需要弄清楚 IntPtr究竟返回了什么,因为如果它是一个公共指针 我不能在MT中使用它。我还认为由于垃圾收集 循环我不能使用内部指针,所以在任何情况下,我需要引脚 托管对象并返回其所在内存的确切地址 开始。我错了
这就是我所想到的,已经测试过了,它可以工作,所以我相信它是正确的实现。

  • 我不应该去想指针,因为我要去工作 使用自定义托管类,该类似乎不是可Blittable类型,并且 可能无法固定。我可以使用一些泛型类型,比如byte 数组,将其固定并使用AddrOfPinnedObject获取实际地址。在这个 案例i可以处理来自托管和非托管的数据 但我决定留在管理层只是为了 简单

  • 我意识到IntPtr是指向数据的指针,有点像void**但对于托管堆,这意味着有两个指针,第一个指向“handle”,而“handle”指向实际数据。如果实际数据被重新定位,第二个指针(“句柄”)可以在GC循环后更改,但该句柄的地址保持不变,这意味着第一个指针在任何情况下都是持久的。我打算只使用托管代码中的数据进行操作,所以只保存第一个指针就足够了,然后,使用这个指针,我总是可以获得“句柄”,不管它的值是否被GC更改。给定句柄-可以自己获取数据

  • 对我来说,int_ptr和interrior_prt模板似乎是一个黑匣子,所以如果我使用它们,那么可能很难理解这些句柄的工作原理,也许我很快就会改变主意,但现在我用GCHandle实现了它

示例:

假设我在C#DLL中有一个类,我想通过内存映射文件将它用作共享内存,我称之为连接:

在C++/CLI中,我有:

#define ECV extern "C" __declspec(dllexport) void __cdecl

ECV MemoryOpen(char * name, int size, int &pointer)
{
    try
    {
        Connection ^ memory = gcnew Connection(); // instantiate managed class
        GCHandle gc = GCHandle::Alloc(memory); // get handle
        pointer = (int) GCHandle::ToIntPtr(gc); // get pointer to handle and pass it to unmanaged code by reference
        memory->Open(gcnew String(name), size); // do something from managed code
    }
    catch (Exception ^ e)
    {
        MessageBox::Show(e->Message + " " + e->StackTrace);
    }
}

ECV MemoryClose(int pointer)
{
    try
    {
        GCHandle gc = GCHandle::FromIntPtr(IntPtr(pointer)); // get pointer to handle
        Connection ^ memory = (Connection ^) gc.Target; // get data using handle
        memory->Close();
        gc.Free(); // free handle
    }
    catch (Exception ^ e)
    {
        MessageBox::Show(e->Message + " " + e->StackTrace);
    }
}

似乎我找到了帮助我理解如何使用IntPtr的解释

以下段落包含错误的建议。

  • 我问什么是IntPtr是因为:我需要移动我所有的 C#library(DLL)的有用函数,同时能够 从非托管程序(如Metatrader)调用它们。不幸的是, Metatrader根本不支持指针,所以我需要弄清楚 IntPtr究竟返回了什么,因为如果它是一个公共指针 我不能在MT中使用它。我还认为由于垃圾收集 循环我不能使用内部指针,所以在任何情况下,我需要引脚 管理产科
    #define ECV extern "C" __declspec(dllexport) void __cdecl
    
    ECV MemoryOpen(char * name, int size, int &pointer)
    {
        try
        {
            Connection ^ memory = gcnew Connection(); // instantiate managed class
            GCHandle gc = GCHandle::Alloc(memory); // get handle
            pointer = (int) GCHandle::ToIntPtr(gc); // get pointer to handle and pass it to unmanaged code by reference
            memory->Open(gcnew String(name), size); // do something from managed code
        }
        catch (Exception ^ e)
        {
            MessageBox::Show(e->Message + " " + e->StackTrace);
        }
    }
    
    ECV MemoryClose(int pointer)
    {
        try
        {
            GCHandle gc = GCHandle::FromIntPtr(IntPtr(pointer)); // get pointer to handle
            Connection ^ memory = (Connection ^) gc.Target; // get data using handle
            memory->Close();
            gc.Free(); // free handle
        }
        catch (Exception ^ e)
        {
            MessageBox::Show(e->Message + " " + e->StackTrace);
        }
    }