Home > Blockchain >  How to cast struct of std:array<char> to single std::array<char>
How to cast struct of std:array<char> to single std::array<char>

Time:10-19

I'm packing messages to be send to another device. I'm using C 11. Usually the payload is a single ASCII encoded value, but this one command has a bit more parameters. I'm trying to pack the payload in a single array of chars. I'm looking for a clean solution, and I thought that the following (example) solution should work:

Message foo(Parameters parameters) {
    struct __attribute__((__packed__)) ParameterPayload {
        std::array<char,2> a;
        std::array<char,2> b;
        std::array<char,2> c; 
        std::array<char,4> d;
    }; // Actual struct has way more parameters
    ParameterPayload paramPayload;
    paramPayload.a = bar<2,10>(parameters.a);
    paramPayload.b = bar<2,10>(parameters.b);
    paramPayload.c = bar<2,10>(parameters.c);
    paramPayload.d = bar<4,16>(parameters.d);
    
    // This will not work, but I want something like this to work
    auto payload =  reinterpreted_cast<std::array<char, sizeof(ParameterPayload)>(paramPayload);

    return baz<sizeof(ParameterPayload)>(payload);
}

template<size_t size, int base>
std::array<char, size> bar(int input> {
    // ASCII encoding with a base (2, 10 or 16)
}

template<size_t payloadSize>
Message baz(std::array<char, payloadSize> payload) {
    // Some packing computation
}

This is a rough example, but I think it will get the message across. How do I cast the struct to a single std:array<char, N>? Is it even possible? I'm trying not to do multiple std::copies instead, because that will cost more resources and will worsen readability.

another solution I looked into is using

const char* const payload = reinterpret_cast<const char* const>(&paramPayload);

and going from there... I could do a single copy after that, but I'd like to avoid it.

CodePudding user response:

That casting is pedantically UB (and even we don't have guaranty of exact size of std::array).

I suggest to change to something like:

Message foo(Parameters parameters) {
    std::array<char, 2 2 2 4> payload; // Actual struct has way more parameters
    int offset = 0;
    bar<2, 10>(parameters.a, payload.data()   offset, offset);
    bar<2, 10>(parameters.b, payload.data()   offset, offset);
    bar<2, 10>(parameters.c, payload.data()   offset, offset);
    bar<4, 16>(parameters.d, payload.data()   offset, offset);

    return baz(payload);
}

template<size_t size, int base>
void bar(int input, char* out, int& offset) /* std::span<char, size> out (in C  20) */
{
    offset  = size;
    // ASCII encoding with a base (2, 10 or 16)
}

template<size_t payloadSize>
Message baz(std::array<char, payloadSize> payload) {
    // Some packing computation
}
  • Related