Приведение к структуре из LPVOID - C - PullRequest
2 голосов
/ 11 марта 2010

Я пишу простое консольное приложение, которое позволит мне создать несколько потоков из набора параметров, передаваемых через аргументы, которые я предоставляю.

DWORD WINAPI ThreadFunc(LPVOID threadData)
{
}

Я упаковываю их в структуру и передаю их в качестве параметра в метод CreateThread и пытаюсь распаковать их, приведя их к тому же типу, что и моя структура из LPVOID.

Я не уверен, как привести его к структуре после прохождения, чтобы я мог использовать его в самом методе, я пробовал различные комбинации (пример присоединен), но он не скомпилируется.

Struct:

#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» в «данные»

Как вы можете видеть, я реализовал способ перебирать несколько сообщений уже, я пытаюсь сделать вещи немного более продвинутыми и добавить некоторые дополнительные функции.

Ответы [ 7 ]

9 голосов
/ 11 марта 2010

ОК, для начала, это взорвется:

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;
    // ...
}
4 голосов
/ 11 марта 2010

Сначала вы создаете только указатель на структуру, но не саму структуру, а затем используете неинициализированный указатель.

struct Data *tData;

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

Вам нужно создать структуру. Если функция, создающая поток, собирается завершить работу до завершения потока, вам необходимо создать его динамически. например,

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

Вы должны убедиться, что структура затем освобождается в соответствующей точке где-то еще, возможно, в конце функции потока, если она не используется в другом месте.

Затем вы пытаетесь привести параметр LPVOID к структуре, где то, что вы передали, является указателем на указатель на вашу структуру. Параметр не будет достаточно большим, чтобы передать всю структуру по значению. Вы, вероятно, хотите передать только указатель на вашу структуру (передать tData, а не &tData в CreateThread, и затем вы можете инициализировать от LPVOID до указателя на вашу структуру. (Так как это C - приведение не требуется, и вам следует избегать ненужных приведений - неправильные могут скрывать подлинные ошибки.)

, например * * 1016

struct Data *tData = threadData;
3 голосов
/ 11 марта 2010

LPVOID входит как указатель на структуру, а не сама структура.Поэтому вам нужно что-то вроде:

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

И затем вам нужно получить доступ к полям с помощью оператора ->:

blahblah = ptData->messages;

ОДНАКО.Вам также не хватает выделенного хранилища для структуры, когда вы ее заполняете, поскольку вы используете указатель без какой-либо резервной памяти.Вам нужно malloc структура.Вы должны прочитать об управлении памятью в C. (Среди многих других ссылок, эта говорит о структурах)

1 голос
/ 11 марта 2010

Вы пытаетесь преобразовать значение указателя (LPVOID эквивалентно void*) в значение без указателя.Это не разрешеноВместо этого вам необходимо преобразовать его в другое значение указателя, например struct Data*.

Попробуйте следующее

struct Data* pData = (struct Data*)threadData;
0 голосов
/ 11 марта 2010

в вашем коде есть другие ошибки ... tData, похоже, не выделен .. также вы передаете его с помощью оператора & address, поэтому вы передаете адрес указателя, а не указателя. Возможно, когда вы получите указатель и используете его, вы получите AccessViolation

0 голосов
/ 11 марта 2010

Заменить на:

struct Data *tData = (struct Data*)threadData; 
0 голосов
/ 11 марта 2010

Приведите ваши данные в функцию CreateThread как LPVOID

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

Также в ThreadFunc Data должны быть данные *

Если вы перейдете к определению LPVOID, вы увидите, что это просто указатель на пустоту. Так как tData уже является указателем, вам не нужен адрес указателя.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...