【问题标题】:How can I correctly downcast the pointer from void* to TMemo* in C++Builder2009?如何在 C++Builder2009 中正确地将指针从 void* 向下转换为 TMemo*?
【发布时间】:2008-11-08 15:45:13
【问题描述】:

我正在 C++Builder 2009 中编写多线程套接字聊天。
根据我需要做的,它几乎完成了,但我有一个小问题。 我需要将 TMemo* 指针传递给 CreateThread WinAPI 函数,该函数将其向上转换为 void*。

我试过这样:

HANDLE xxx = MemoChat->Handle;
hNetThread = CreateThread(NULL, 0, NetThread, xxx, 0, &dwNetThreadId);
//...

然后,在 NetThread 函数中,

TMemo* MyMemo((HANDLE)lpParam);
TMemo* MyMemo((TMemo*)lpParam);

但它没有工作:(

问题是我如何才能真正正确地向下转换,以便可以在这个新线程中使用我的备忘录组件?

【问题讨论】:

    标签: c++ c++builder downcast tmemo


    【解决方案1】:

    呼叫:

    TMemo*     MemoChat   = // You defined that somewhere I assume
    HANDLE     hNetThread = CreateThread(NULL, 0, NetThread, MemoChat, 0, &dwNetThreadId);
    

    这里发生的情况是,作为第三个参数传递的任何指针都将自动转换为 void 指针(或在 WinTerms LPVOID 中)。没关系,它不会改变它,它只会丢失类型信息,因为系统对您的对象一无所知。

    新的线程起点:

    DWORD NetThread(LPVOID lpParameter)
    {
        TMemo*   MemoChat   = reinterpret_cast<TMemo*>(lpParameter);
        // Do your thread stuff here.
    }
    

    一旦你的线程启动方法被调用。只需将 void 指针转换回正确的类型,您就可以再次开始使用它了。

    只是为了澄清其他误解。

    HANDLE 是一个指针
    您可以将它作为参数传递给 NetThread()。

    句柄是指向系统控制下的指针的指针,它指向您正在使用的对象。那么为什么要使用双重间接。它允许系统移动对象(并更新其指针)而无需找到对象的所有所有者。所有者都有指向刚刚更新的指针的句柄。

    这是一个老式的计算机科学概念,在现代计算机中很少使用,因为操作系统/硬件能够将主内存交换为辅助存储。但对于某些资源,它们仍然有用。如今,当需要手柄时,它们隐藏在远离用户的物体内。

    【讨论】:

    • 我以为它s better never use reintepret_cast. So, your post means Im 错了。:)
    • 是的,最好不要使用 reinterpret_cast(),但这是您必须使用它的少数情况之一。您需要使用它的事实表明,事情可能会出错,您应该仔细检查您是否真的转换为正确的类型。
    • 指针,间接引用。同样的事情:-)
    【解决方案2】:

    请理解 HANDLE 不是指针,而是 Win32 API 的一个概念。所以第一行将 LPVOID 转换为 HANDLE - 这是正确的,因为线程例程的参数实际上是作为句柄 (xxx) 给出的。但是,它会继续将 HANDLE 转换为 MyMemo 对象;这会将句柄中的位视为将形成一个地址 - 它们不是。

    第二行执行完全相同的转换 - 它将句柄直接视为指针。

    我想知道您为什么不将 MemoChat 本身传递给线程:

    hNetThread = CreateThread(NULL, 0, NetThread, MemoChat, 0, &dwNetThreadId);
    

    【讨论】:

    • 手柄不是赢 32 的东西。句柄是一个定义明确的计算机科学概念。它是一个指针 t 一个指针。第二个指针在系统控制下的位置。从而允许系统动态移动内存块而不影响手柄的持有者。
    • msdn.microsoft.com/en-us/library/ms724457(VS.85).aspx。 “每个句柄在内部维护的表中都有一个条目。” Win32 HANDLE 是通用 CS 句柄概念的具体实现。
    • 我想,这正是我之前所说的!
    • 句柄不是指针,尽管它是 void* 的 typedef。 指针 是内存中的地址。 HANDLE 是一个不透明的值;大多数情况下,它是进程句柄表的索引(不是指针)。
    • 我认为您在实现细节上分心,没有抓住重点。无论它是如何实现的,都可以将其视为指向指针的指针(或间接引用)。因此,它可以在此上下文中用作指针(毕竟它只是一个美化的 void* 或 LPVOID)。试试吧,它会很好用的:-)
    【解决方案3】:

    这更多是为了尝试澄清句柄与指针的关系,因为我认为 Martin 的说法并不完全正确。

    “指向指针的指针”确实称为 HANDLE,它是一种常见的 CS 方法,允许操作系统在不明确知道应用层的情况下物理移动堆分配的内存块,应用层总是通过以下方式访问它们手柄。 Classic 68K Mac OS 以这种方式工作。以这种方式工作的操作系统通常允许用户代码通过句柄以及直接在堆外分配内存。这种方法用于没有适当内存管理硬件的机器上。

    但是,HANDLE 这个词还有其他用法,它们借用了之前用法的一些抽象,但有不同的实现。不透明指针(指向用户不知道的数据结构的指针 - PIMPL 习惯用法)通常也称为 HANDLES。

    此外,术语 HANDLE 可以简单地用于表示对对象的“引用”——可能是数组的索引。 Unix 文件句柄(= 文件描述符)就是一个很好的例子。标准输入=0,标准输出=1,...

    那么,以上哪些是 Windows API HANDLES?我看到了相互矛盾的报道。 This document 说:

    Win32 中的句柄是用于 识别资源或窗口。他们 不是指针或指向 指针。将它们视为 ID 号。

    【讨论】:

    • 在 Win32 中,句柄(这是 typedef 的实际名称)绝对不是指针(即内存地址)。相反,它是一个不透明的值——对于内核句柄来说,它是一个索引(指向位于内核内存中的表)。见cs.miami.edu/~burt/journal/NT/handle_table.html
    • 是间接引用。相同的概念不同的实现。
    • @Martin 诉 Lowis。谢谢 - 很好的链接。 Windows 通过“typedef void* HANDLE”混淆了这个问题。
    • @Martin Y:同意-但您的答案是将“指针对指针”实现作为唯一的实现,并暗示这就是 Windows 的工作方式。当然,除非我们对指针的构成存在分歧...... ;-)
    猜你喜欢
    • 1970-01-01
    • 2010-12-14
    • 1970-01-01
    • 2011-10-27
    • 2021-09-20
    • 2011-02-06
    • 2021-07-22
    • 1970-01-01
    相关资源
    最近更新 更多