从LPVOID转换为结构体 - C

4
我正在编写一个简单的控制台应用程序,可以通过提供的参数创建一些线程。
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)
                           );

My attempt:

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' 转换为 'Data'

正如您所看到的,我已经实现了一种方法来循环处理一些消息,我正在尝试使事情稍微更加高级并添加一些进一步的功能。


我已经标记了正确的答案,但根本问题在于你不理解指针或动态分配,因此你还没有准备好进行线程处理。 - Steven Sudit
我有一定的理解,接下来我会阅读给出答案的相关信息。 - Jamie Keeling
7个回答

10

好的,首先,这将会爆炸:

struct Data *tData;

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

你创建了一个指向结构体的指针类型变量,但你没有将该指针初始化为指向任何内容。tData 是未初始化的,所以你正在写入一个 野指针

你可能需要像这样进行初始化:

// 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;
    // ...
}

1
非常感谢您的详细解释,我来自C#背景,所以指针等概念对我来说还是比较新的。 - Jamie Keeling

4

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

struct Data *tData;

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

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

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

您应该确保在适当的时候释放结构体,可能是在线程函数结束时,如果它没有在其他地方使用。

然后,您尝试将LPVOID参数转换为结构体,而您传递的是指向指针的指针。该参数不足以按值传递整个结构体。您可能只想传递指向您的结构体的指针(将tData而不是&tData传递给CreateThread,然后您可以从LPVOID初始化为指向您的结构体的指针。 (由于这是C语言,因此不需要进行强制类型转换,并且应避免不必要的转换-错误的转换可能掩盖真正的错误。)

例如:

struct Data *tData = threadData;

3
LPVOID作为指向结构体的指针传入,而不是结构体本身。因此您需要类似这样的内容:
struct Data * ptData = (struct Data *)threadData;

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

blahblah = ptData->messages;

然而,当你填写结构体时,你还缺少为其分配存储空间,因为你使用了一个没有任何后备内存的指针。你需要使用malloc函数来分配结构体的内存空间。你应该学习C语言中的内存管理知识。(在众多链接中,这个链接讨论了结构体)


1

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

请尝试以下操作:

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

0
将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已经是一个指针,你就不需要指针的地址了。


0

替换为:

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

0

你的代码中还有其他错误... tData 似乎没有被分配内存.. 而且你使用了 &address 操作符来传递它,所以你传递的是指针的地址而不是指针本身。可能当你获取指针并使用它时会出现访问冲突。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接