Использование Embarcadero C++ Builder 10.3.
У меня есть объект DynamicArray<uint8_t> myData. Я хочу отправить/записать необработанный двоичный контент (байты) на сервер с помощью компонента TIdTcpClient. Я поступаю так:
TIdTcpClient tcpClient1;
// Bla Bla Bla
tcpClient1->IOHandler->Write(rawData);
Где rawData должен быть типа TIdBytes или TIdStream
Итак, в основном все сводится к следующему: как преобразовать myData объект в rawData тип TIdBytes или TIdStream?





Во-первых, TIdStream не был частью Indy ОЧЕНЬ ОЧЕНЬ ДОЛГО, что заставляет меня задуматься, используете ли вы очень старую версию Indy, а не ту, которая поставляется с C++Builder 10.3. Indy уже очень давно поддерживает стандартный класс RTL TStream.
Что, как говорится...
TIdBytes — это псевдоним для System::DynamicArray<System::Byte>, где System::Byte — это псевдоним для unsigned char, который имеет тот же размер и знак, что и uint8_t (в зависимости от компилятора, uint8_t может даже быть просто псевдонимом для unsigned char).
Таким образом, самое простое решение, когда без необходимо сделать отдельную копию ваших данных, — это просто привести ее к типу, например:
tcpClient1->IOHandler->Write(reinterpret_cast<TIdBytes&>(myData));
Технически это неопределенное поведение, поскольку DynamicArray<uint8_t> и DynamicArray<Byte> являются несвязанными типами (если только uint8_t и Byte не являются псевдонимами для unsigned char), но это будет работать в вашем случае, поскольку это один и тот же базовый код для обоих массивов, а uint8_t и Byte имеют одинаковую базовую основу макет памяти.
В качестве альтернативы, следующее простейшее решение, копирование данных без или вызов неопределенного поведения, заключается в использовании класса Indy TIdReadOnlyMemoryBufferStream в IdGlobal.hpp, например:
TIdReadOnlyMemoryBufferStream *ms = new TIdReadOnlyMemoryBufferStream(&myData[0], myData.Length);
try {
tcpClient1->IOHandler->Write(ms);
}
__finally {
delete ms;
}
Или:
{
auto ms = std::make_unique<TIdReadOnlyMemoryBufferStream>(&myData[0], myData.Length);
tcpClient1->IOHandler->Write(ms.get());
}
В противном случае окончательным решением будет просто скопировать данные в TIdBytes, например:
{
TIdBytes bytes;
bytes.Length = myData.Length;
memcpy(&bytes[0], &myData[0], myData.Length);
or:
std::copy(myData.begin(), myData.end(), bytes.begin());
tcpClient1->IOHandler->Write(bytes);
}
Документация Indy очень старая, она давно не обновлялась. В этом случае TIdIOHandler.Write (TIdStream, Int64, Boolean) теперь TIdIOHandler.Write (TStream, Int64, Boolean)
Согласно документации Indy, поставляемой с C++ Builder 10.3, одной из перегрузок метода
IOHandlerвWriteявляетсяTIdIOHandler.Write (TIdStream, Int64, Boolean). Согласноstdint.h,uint8_tопределяется не какtypedef unsigned char, а какtypedef unsigned __int8, где__int8— расширенный интегральный тип фиксированной длины. При этом я не думаю, что поведение undefined будет проблемой. Еще лучше заменить моиuint8_ts наSystem::Byte.