rmds Ответов: 4

Как преобразовать char* в struct. Возможен ли такой актерский состав?


Моя структура:
typedef enum {
    SEND_FILE       =   0,
    FILE_SIZE       =   10,
}CommandList;

typedef struct {
    CommandList command;
    char DataBuffer[PAYLOAD_SIZE];
} COMMAND_HEADER;

struct Command_Data {
    char message;
};

void some_unnamed_function() {
   ...
   COMMAND_HEADER command_header;
   command_header.command = SEND_FILE;
   ULONGLONG dwLength = Sourcefile.GetLength();
   char* buffer = new char[(int)dwLength + 1];
   buffer[dwLength] = 0;
   UINT nActual = Sourcefile.Read(buffer, dwLength);
   Command_Data *tmp_str = (Command_Data *)buffer;
   //Buffer contains text file. 
   int nfRet = SockConnection.Send((char*)&command_header, sizeof(command_header));

   //Command_Data *tmp_str = (Command_Data *)buffer;//trying to type cast from char* to struct.

   ...
}

Я передаю файл через команду structure в CSocket. Но, не уверен, что char* to struct является правильным. Пожалуйста, сделайте это правильно.

Что я уже пробовал:

UINT nActual = исходный файл.Чтение(буфер, dwLength);
//Buffer содержит текстовый файл.

Command_Data *tmp_str = (Command_Data *)буфер;

int nfRet = SockConnection.Send((char*)&command_header, sizeof(command_header));

Stefan_Lang

Код, который вы опубликовали, является неполным и оставляет нас гадать, что отсутствует или неправильно.
По крайней мере, я не вижу объявления переменной command_header.

Существует также одна вероятная ошибка в структуре Command_Data: сообщение переменной - члена объявляется как тип char-не должно ли оно быть массивом или указателем на char вместо этого? трудно сказать, каковы были ваши намерения.

rmds

Моя вина! Я скучал по ним...
COMMAND_HEADER command_header;
command_header.command = SEND_FILE;
ULONGLONG dwLength = исходный файл.Метода getlength может служить метод();
char* buffer = new char[(int)dwLength + 1];
буфер[dwLength] = 0;
UINT nActual = исходный файл.Чтение(буфер, dwLength);
Command_Data *tmp_str = (Command_Data *)буфер;
//Buffer содержит текстовый файл.
int nfRet = SockConnection.Send((char*)&command_header, sizeof(command_header));

//Command_Data *tmp_str = (Command_Data *)buffer;//попытка ввести приведение из char* в struct.

Stefan_Lang

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

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

rmds

Спасибо, но уже опубликованный код-это почти все.
Кстати я нашел способ приведения типа из char* в структуру.

"Command_Data* tmp_str = оператора reinterpret_cast&ЛТ;Command_Data*&ГТ;(буфер);"
Теперь нужно скопировать эти данные в буфер сообщений [Command_Data]. Я изменил его на массив.. Как это сделать?

4 Ответов

Рейтинг:
32

Stefan_Lang

Есть несколько проблем, которые я вижу с вашим кодом.

1. Ваша переменная command_header не инициализируется полностью: назначается только команда, но вы никогда не заполняете ее буфер данных. Вы хотели прочитать данные из исходного файла в этот буфер? Если это так, вам нужно скопировать его из буфера и убедиться, что вы не превышаете PAYLOAD_SIZE.

2. Определение Command_Data кажется неправильным. Он содержит только один символ так, как он объявлен в вашем коде. Непонятно, для чего эта структура предназначена и используется.

3. tmp_str никогда не используется. Поэтому трудно сказать, имеет ли это назначение смысл или как его улучшить.

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

С. П.:
После большого количества дополнительной информации и некоторых обоснованных предположений я думаю, что именно так должен выглядеть ваш код:

enum Command {
   SEND_FILE       =   0,
   FILE_SIZE       =   10,
};
struct FileSizeMsg {
   Command command;
   int file_size;
};
struct FileSendMsg {
   Command command;
   char data[]; // see below
};
int send_text_file(CFile& Sourcefile) {

   // get size of file
   ULONGLONG dwLength = Sourcefile.GetLength();
   // read file into buffer
   char* buffer = new char[(int)dwLength + 1];
   UINT nActual = Sourcefile.Read(buffer, dwLength);
   buffer[dwLength] = 0; // just in case Read() does not add a terminating 0-byte
   // find out real string length
   size_t real_length = strlen(buffer);

   // prepare first message: the file size
   FileSizeMsg size_msg;
   size_msg.command = FILE_SIZE;
   size_msg.file_size = (int)real_length;
   // send file size message
   int nfRet = SockConnection.Send((char*)&size_msg, sizeof(size_msg));

   // second message: the actual data
   // dynamically allocate a sufficiently large memory block
   int full_length = (int)sizeof(Command) + real_length + 1;
   char* full_message = new char[full_length];
   // reuse that memory block as a FileSendMsg object and fill its data members
   FileSendMsg* send_msg = reinterpret_cast<FileSendMsg*>(full_message);
   send_msg->command = SEND_FILE; // this assignment writes to the first byte(s) of full_message
   strncpy(send_msg->data, buffer, real_length + 1);
   // now send the full memory block
   nfRet = SockConnection.Send(full_message, full_length);

   delete [] buffer;
   delete [] full_message;
   return nfRet;
}

Это предполагает, что получатель этих сообщений ожидает сообщение информации о размере, отделенное от фактических данных. (иначе зачем вводить две разные команды?).

Обратите внимание, как FileSendMsg.data объявляется в качестве заполнителя для строки произвольной длины. Его нельзя использовать обычным способом, но если вы отделите выделение памяти от использования этой структуры, он будет вести себя как класс объектов с динамическим размером.


rmds

command_header-это структура объекта Command_Data. и да, я читаю данные из исходного файла в этот буфер. Я также изменил определение командных данных на:

структура Command_Data {
сообщение char[1000];
};

Все, что я хочу, это скопировать буфер, содержащий данные из файла, в это " char message[1000]" в приведенной выше структуре.

Stefan_Lang

Вы можете использовать memcpy:
mempy(comand_header.DataBuffer, буфер, std::min(1000, nActual));

Видишь ли http://www.cplusplus.com/reference/cstring/memcpy/

Если тип данных на самом деле текстовый, то вместо него можно использовать strncpy.

rmds

Большое спасибо...Каким-то образом этот memcpy тоже читает мусорные значения в конце...вот что я попробовал:
memcpy(command_header.Message_Buffer, буфер, /*min(1000, nActual)*/nActual);
буфер[nActual] = '\0';
int nRet = m_SocketConnection.Send((char*)&command_header,
оператор sizeof(command_header));

Stefan_Lang

Если файл содержит текст, вам нужен strncpy, а не memcpy - тот же синтаксис, но strncpy автоматически остановится на 0-Терминаторе. Кроме того, вам может потребоваться добавить 0 байт в целевой буфер в конце, если он не будет считан из файла. Видишь ли http://www.cplusplus.com/reference/cstring/strncpy/ для документации и примера кода.

Stefan_Lang

P.S.: предполагая, что nActual меньше 1000, вам, возможно, следует уменьшить размер сообщения, которое вы отправляете в этой последней строке, с sizeof(command_header) до sizeof(command_header)-1000+nActual+1
(+1 для завершения 0 байт)

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

Stefan_Lang

P. P. S.: Я обновил свое решение с помощью примера кода. Он должен работать как есть, за исключением того, что в нем отсутствует объявление SockConnection.

Рейтинг:
26

Richard MacCutchan

В любом случае вам не нужна структура. Заголовок вашей команды-это одно значение (байт?) который вы передаете самостоятельно, а затем буфер символов считывается из входного файла. Вам также необходимо изменить свой код чтения, поскольку вы делаете вещи в неправильном порядке. Так и должно быть:

typedef enum {
    SEND_FILE       =   0,
    FILE_SIZE       =   10,
}CommandList;

void some_unnamed_function() {

    CommandList command;
    char *DataBuffer;
    
   command = SEND_FILE;
   ULONGLONG dwLength = Sourcefile.GetLength();
   DataBuffer = new char[(int)dwLength + 1];
   UINT nActual = Sourcefile.Read(buffer, dwLength);
   DataBuffer[nActual] = 0;
   //Buffer contains text file. 
   int nfRet = SockConnection.Send((char*)&command, sizeof(command));
   nfRet = SockConnection.Send(DataBuffer, nActual);


   ...
}


Рейтинг:
2

steveb

Чтобы привести структуру к char* buffer, вам нужно выделить буфер структуры sizeof. Затем вы можете использовать memcpy при приведении структуры к символу char*

Пример:

struct blah
{
    int i;
    float f;
};

blah b = {10, 2.75};
char buffer[8]; // sizeof(blah) == 8

memcpy(buffer, (char*)&b, sizeof(blah));


rmds

На самом деле мой-это char* to struct. Пытался:
метод 1. memcpy(command_header.Message_Buffer, буфер, nActual);
буфер[nActual] = '\0';

метод 2. memset(command_header.DataBuffer, '\0', sizeof(command_header.Databuffer, с));
strcpy(command_header.Буфер данных, буфер);

Оба этих метода также считывают данные вместе с ненужными значениями.

steveb

Когда вы копируете массив символов в структуру, вы делаете это с указателем структуры, предполагая, что Ваш массив символов содержит всю структуру, т. е.

структура бла б;
memcpy(&b, buffer, sizeof(бла));

Рейтинг:
2

KarstenK

Приведение типов не означает, что код становится более валидным или лучшим. Более того, каждый приведенный тип делает ваш код более опасным и проблематичным.

Вы должны предоставить достаточно памяти и работать с ней правильно. Представьте, что указатели адресов в памяти. Если память не является действительной, она рухнет рано или поздно!!!.


rmds

Согласен! Пожалуйста, помогите мне избавиться от мусорных значений в вышеуказанной ситуации. Спасибо