1

I have a library that produces std::vector<uint8_t>'s, I have an API which consumes std::vector<char>'s. I find myself in need of getting from point A to point B.

The line I'm using to do this right now is considered "bad" by most.

std::vector<std::uint8_t> in {...};
std::vector<char> out;
out = reinterpret_cast<std::vector<char>&&>(in);

But it produces reasonable code, and as a practical matter works everywhere despite being a straightforward violation of strict aliasing. I'm wondering if anyone has a clean way of doing this that doesn't anger the language lawyers and will keep me in the good graces of the compiler gods.

I know this code is bad, please do not tell me this code is bad/UB/call me a felon. I'm admitting to that up front. I'm also uninterested in the obviously correct answers that involve copying the vector, clearly trying to avoid the copy here.

nickelpro
  • 2,537
  • 1
  • 19
  • 25
  • 1
    @Casey Of course they can? uint8_t {255} == char {-1}? – nickelpro May 06 '21 at 07:52
  • I'm mistaken. Converting from `unsigned char`/`uint8_t` to `char` and back is [guarenteed to produce the original value](https://en.cppreference.com/w/cpp/language/types#Character_types). – Casey May 06 '21 at 07:58
  • @TedLyngmo Alas, they require new types that the API I'm using does not know how to consume, and so does not answer my question. The answer to this question is apparently, "No, there is no other way" – nickelpro May 06 '21 at 08:30
  • 1
    @nickelpro Ok, I've opened the question again since my proposed [duplicate](https://stackoverflow.com/questions/62505019/assign-stdvectorstdbyte-to-stdvectorchar-without-copying-memory/62505567#62505567) doesn't cut it. – Ted Lyngmo May 06 '21 at 08:35
  • So, you are not in control of either side (the library or the API)? – Ted Lyngmo May 06 '21 at 08:39
  • 1
    @TedLyngmo Nope, library is [Botan](https://botan.randombit.net/) producing an encrypted byte buffer, which for some reason prefers uint8_t. The API is a network serializer I don't have control over. – nickelpro May 06 '21 at 08:42
  • And they both only accept a `std::vector<>` with their prefered type in it? There is no "raw" interface taking iterators or even `char*, size_t`? What's the name of the API? Can you also link directly to the Botan function you use to get the `vector`? – Ted Lyngmo May 06 '21 at 08:50
  • I'm just populating fields in a struct, that struct gets sent to the serializer to actually blit to the wire. In this case, the field is an RSA encrypted secret. The struct I'm sending to the serializer has this field as a vector, and Botan produces a vector. Believe me if I had another option here I wouldn't have bothered asking. The serializer is a requirement, Botan is already in the codebase which is why I'm using it. – nickelpro May 06 '21 at 08:57
  • "_if I had another option_" - Sure, but I thought two sets of eyes are better than one :-) "_Botan produces a vector._" - which Botan function? Can you link to it? What is the name of the serializer? – Ted Lyngmo May 06 '21 at 10:00
  • I appreciate you taking the time! The Botan class is a [PK_Encryptor_EME](https://github.com/randombit/botan/blob/master/src/lib/pubkey/pubkey.h#L500), with this [encryption signature](https://github.com/randombit/botan/blob/master/src/lib/pubkey/pubkey.h#L41-L52). The serializer is internal, but functionally [works like this](https://godbolt.org/z/KP4hfosjh). – nickelpro May 06 '21 at 10:26
  • It looks like it would be possible to create your own Botan classes to provide a `char` based interface. Down at the lower levels there's always a call to a `uint8_t* in, size_t, uint8_t* out` -like function. At that level you could `reinterpret_cast` your `char*`'s. A simpler way would be to use `uint8_t` in your own serializer. That would have been a better choice to start with. – Ted Lyngmo May 06 '21 at 12:14

0 Answers0