从LPVOID铸造结构 - C

问题描述:

我正在写一个简单的控制台应用程序,它将允许我通过通过我提供的参数传递的一组参数创建一些线程。从LPVOID铸造结构 - C

DWORD WINAPI ThreadFunc(LPVOID threadData) 
{ 
} 

我包装他们进入一个结构和将它们作为参数传入的CreateThread的方法,并试图通过他们铸造的同类型从LPVOID我的结构解压它们。

我不知道如何将它转换到结构后,所以我可以在方法本身使用它,我试过各种组合(例如attatched),但它不会编译。

结构:

#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'转换为'数据'

正如你所看到的,我已经实现了一种方法来循环遍历一些消息,我试图让事情稍微更先进,并添加一些更多的功能。

+0

我已经标记了正确的答案,但底层的问题是你不明白指针或动态分配,所以你还没准备好进行线程化。 – 2010-03-11 18:38:24

+0

我的理解程度,我会在给出答案后再读。 – 2010-03-11 18:54:00

OK,对于初学者来说,这是要炸毁:

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! 
         ...); 

你可能想通过指针的值(struct的地址,它指向):

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

感谢您的详细解释,我来自C#背景,所以指针等概念对我来说是相当新的。 – 2010-03-11 18:55:03

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

请尝试以下

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

在CreateThread函数你要把你的数据作为LPVOID

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

而且ThreadFunc中的数据应该是数据*

如果你去definitaion LPVOID你会看到它只是一个指向void的指针。所以既然tData已经是一个指针了,你不需要指针的地址。

替换:

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

的LPVOID即将作为一个指针结构,而不是结构本身。所以,你想要的东西,如:

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

然后你需要与运营商->访问字段:

blahblah = ptData->messages; 

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

+0

感谢您的解释 – 2010-03-11 18:54:38

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

struct Data *tData; 

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

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

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

您应该确保结构,然后在适当的点在其他地方释放,或许在线程函数结束时,如果它不是在别处使用。

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

struct Data *tData = threadData; 
+0

感谢您的回答 – 2010-03-11 18:55:40

有在你的代码其他错误...... TDATA似乎没有分配..你也与&地址运营商通过它,所以你。正在传递指针的地址而不是指针。可能当你得到指针并使用它时,你会得到一个AccessViolati在