【问题标题】:Casting to a struct from LPVOID - C从 LPVOID 转换为结构 - C
【发布时间】:2010-03-12 02:48:07
【问题描述】:

我正在编写一个简单的控制台应用程序,它允许我从一组通过我提供的参数传递的参数创建多个线程。

DWORD WINAPI ThreadFunc(LPVOID threadData)
{
}

我将它们打包到一个结构中,并将它们作为参数传递给 CreateThread 方法,并尝试通过将它们从 LPVOID 转换为与我的结构相同的类型来解压它们。

我不确定如何在通过后将其转换为结构,以便我可以在方法本身中使用它,我尝试了各种组合(附加示例)但它不会编译。

结构:

#define numThreads 1

struct Data
{
    int threads;
    int delay;
    int messages;
};

调用方法:

HANDLE hThread;
    DWORD threadId;
    struct Data *tData;

    tData->threads = numThreads;
    tData->messages = 3;
    tData->delay = 1000;


    // Create child thread
    hThread = CreateThread(
                            NULL,       // lpThreadAttributes (default)
                            0,          // dwStackSize (default)
                            ThreadFunc, // lpStartAddress
                            &tData,     // lpParameter
                            0,          // dwCreationFlags
                            &threadId   // lpThreadId (returned by function)
                           );

我的尝试:

DWORD WINAPI ThreadFunc(LPVOID threadData)
    {
        struct Data tData = (struct Data)threadData;

        int msg;

        for(msg = 0; msg<5; msg++)
        {
            printf("Message %d from child\n", msg);
        }
        return 0;
}

编译器错误:

错误 C2440:“类型转换”:无法从“LPVOID”转换为“数据”

如您所见,我已经实现了一种循环遍历多个消息的方法,我正在尝试使事情变得更高级并添加一些进一步的功能。

【问题讨论】:

  • 我已经标记了正确的答案,但根本问题是你不了解指针或动态分配,所以你还没有准备好线程。
  • 我在一定程度上理解,我将按照给出的答案阅读它们。

标签: c winapi


【解决方案1】:

好的,对于初学者来说,这会爆炸:

struct Data *tData;

tData->threads = numThreads;
tData->messages = 3;
tData->delay = 1000;

...因为您已经创建了一个“指向结构的指针”类型的变量,但是您还没有初始化指针以指向任何东西。 tData 未初始化,因此您正在写入 wild 指针

你可能想要这样的东西:

// Allocate memory for the struct on the heap
struct Data *tData = malloc( sizeof(struct Data) );

// Initialize _all_ fields of the struct (malloc won't zero fill)
tData->threads = numThreads;
tData->messages = 3;
tData->delay = 1000;

其次,您传递的是tData地址tData 变量所在的内存位置),而不是tData 在内存中的位置指向

// Create child thread
hThread = CreateThread( ...,
                        &tData, // OOPS - ADDRESS OF THE POINTER VARIABLE ITSELF!
                        ... );

您可能想要传递指针的值(它指向的结构的地址):

// Create child thread
hThread = CreateThread( ...,
                        tData,  // Value of the pointer
                        ... );

当您在回调函数中收到结构体的地址时,将其转换回原来的指向结构体的指针类型,取消引用并享受:

DWORD WINAPI ThreadFunc(LPVOID threadData)
{
    struct Data *tData = (struct Data *)threadData;

    int numMessages = tData->messages;
    // ...
}

【讨论】:

  • 感谢您的详细解释,我来自 C# 背景,所以指针等概念对我来说相当新。
【解决方案2】:

首先,您只创建一个指向结构的指针而不是结构本身,然后使用未初始化的指针。

struct Data *tData;

tData->threads = numThreads;
tData->messages = 3;
tData->delay = 1000;

您需要创建一个结构。如果创建线程的函数将在线程完成之前退出,那么您需要动态创建它。例如

struct Data *tData = malloc(sizeof *tData);

您应该确保该结构随后在其他地方的适当位置被释放,如果它没有在其他地方使用,则可能在线程函数的末尾。

然后您尝试将LPVOID 参数转换为结构,其中您传递的是指向您的结构的指针的指针。该参数不会大到足以按值传递整个结构。您可能只想传入一个指向您的结构的指针(传入tData 而不是&amp;tDataCreateThread,然后您可以从LPVOID 初始化为指向您的结构的指针。(因为这是C 强制转换不是必需的,您应该避免不必要的强制转换 - 不正确的强制转换会掩盖真正的错误。)

例如

struct Data *tData = threadData;

【讨论】:

    【解决方案3】:

    LPVOID 作为指向结构的指针,而不是结构本身。所以你会想要这样的东西:

    struct Data * ptData = (struct Data *)threadData;
    

    然后您需要使用-&gt; 运算符访问字段:

    blahblah = ptData->messages;
    

    但是。填充结构时,您还缺少为结构分配的存储空间,因为您使用的是没有任何后备内存的指针。您需要malloc 结构。您应该阅读 C 中的内存管理。(在许多其他链接中,this one 谈论结构)

    【讨论】:

      【解决方案4】:

      您正在尝试将指针值(LPVOID 等同于 void*)转换为非指针值。这是不允许的。相反,您需要将其转换为不同的指针值,例如struct Data*

      试试下面的

      struct Data* pData = (struct Data*)threadData;
      

      【讨论】:

        【解决方案5】:

        在 CreateThread 函数中将数据转换为 LPVOID

        hThread = CreateThread(
                                NULL,       // lpThreadAttributes (default)
                                0,          // dwStackSize (default)
                                ThreadFunc, // lpStartAddress
                                (LPVOID)tData,     // lpParameter
                                0,          // dwCreationFlags
                                &threadId   // lpThreadId (returned by function)
                               )
        

        同样在 ThreadFunc 中 Data 应该是一个 Data*

        如果您查看 LPVOID 的定义,您会发现它只是一个指向 void 的指针。所以由于 tData 已经是一个指针,所以不需要指针的地址。

        【讨论】:

          【解决方案6】:

          替换为:

          struct Data *tData = (struct Data*)threadData; 
          

          【讨论】:

            【解决方案7】:

            您的代码中还有其他错误... tData 似乎没有分配.. 您也使用 &address 运算符传递它,因此您传递的是指针的地址而不是指针。可能当您获得指针并使用它时,您会获得 AccessViolation

            【讨论】:

              猜你喜欢
              • 2014-12-07
              • 1970-01-01
              • 2012-04-03
              • 1970-01-01
              • 2021-10-27
              • 2015-07-01
              • 2016-09-10
              • 1970-01-01
              • 2014-06-27
              相关资源
              最近更新 更多