Использование 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_t
s наSystem::Byte
.