0

I’m implementing a protocol in C++, and it’s an ongoing project therefore the protocol changes frequently, and I have to change the code accordingly.

Let’s say I define a message as follows:

struct Message {
  const int MSG_LENGTH = 3; // sizeof(a) + sizeof(b)
  uint8_t a;
  uint16_t b;
};

Now I want to add a new field uint32_t c into Message, but I don’t want to manually change MSG_LENGTH.

Is it possible to use some trick (macro or template) to achieve this?

Thanks.

tadman
  • 208,517
  • 23
  • 234
  • 262
Qiao
  • 452
  • 5
  • 15
  • 2
    Assuming the code in your question is the actual code, then just use `sizeof(struct Message)` – Mark Benningfield May 04 '21 at 16:38
  • 1
    What you ask is not possible, though, why don't you use `sizeof(Message)`? Also with that you avoid having a copy of the number `3` in each instance of `Message`. – al3c May 04 '21 at 16:38
  • @MarkBenningfield Thanks for the reply. It’s not actual code, and indeed the Message will inherit from another base struct MessageBase which contains some other member variables, therefore sizeof(Message) is not applicable. – Qiao May 04 '21 at 16:44
  • Then you could use `sizeof(Message) - sizeof(MessageBase)`. –  May 04 '21 at 16:44
  • @jabaa that will not work generally – 463035818_is_not_an_ai May 04 '21 at 16:45
  • If you don't want to change the value _manually_, why is `sizeof(a) + sizeof(b)` commented out? Surely there's some way that you can use `sizeof` to determine the size of a structure – Tim Randall May 04 '21 at 16:49
  • Without some kind of serialization step this struct won't make any sense by itself. You may want to think in terms of templates for automatically encoding these and generating the struct in the first place. – tadman May 04 '21 at 16:50
  • @MarkBenningfield -- the two are not required to be the same, and usually they are not. Structs have padding between and after their fields, so the size of a struct will often be greater than the sum of the sizes of its members. – Pete Becker May 04 '21 at 17:30
  • @PeteBecker: Initially, this was tagged with the [c] tag, and as I pointed out, the suggestion is dependent on the specified code being the actual code. In C, for that code, the prevalent platforms would not pad that structure. – Mark Benningfield May 04 '21 at 17:34
  • @MarkBenningfield -- "the **prevalent platforms** would not pad that structure" -- that's my point: this is not **required** to work. – Pete Becker May 04 '21 at 17:38
  • No reflection yet in c++, but some library offer syntax to add it (`BOOST_FUSION_DEFINE_STRUCT`](https://www.boost.org/doc/libs/1_76_0/libs/fusion/doc/html/fusion/adapted/define_struct.html)), and then you can iterate over members. [`magic_get`](https://github.com/apolukhin/magic_get) is an alternative if your struct has "good" properties. – Jarod42 May 05 '21 at 07:48

1 Answers1

2

One idea could be to define the messages in form of std::tuples:

#include <cstddef>
#include <cstdint>
#include <iostream>
#include <tuple>

template<class... Types>
struct MessageBase : std::tuple<Types...> {
    static constexpr size_t MSG_LENGTH() {
        return (sizeof(Types) + ...);       // calc the size of the fields
    }
};

struct Message : MessageBase<uint8_t, uint16_t> {};

int main() {
    constexpr auto x = Message::MSG_LENGTH();

    std::cout << x << '\n'; //  prints 3
}
Ted Lyngmo
  • 93,841
  • 5
  • 60
  • 108