0

I have an array like this one below:

std::array<char, 10> numbers = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

I have to add 2 more bytes that would represent the checksum of the array.
The checksum is calculated like this:

char x = 0;
char y = 0;

for (int i = 0; i < size; i++)
{
    x = x + array[i];
    y = x + y;
}

Finally, the values x and y should be added at the end array.

I want the array to be static inside a method of a class. I don't know if that matters.

class Foo
{
 public:
  char * getData(void)
  {
    static std::array<char, 10> numbers = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    // checksum must be calculated here.
    return &numbers[0];
  }
}

If I leave two extra bytes space in the array and pass it by reference in a constexpr function. Would that work?

constexpr void checksum_calc(std::array<char, 12>& arr)
{
  char x = 0;
  char y = 0;
  
  for (int i = 0; i < 12 - 2; i++)
  {
      x = x + array[i];
      y = x + y;
  }
  arr[10] = x;
  arr[11] = y;
}

Also, if I want the array to work on different sizes, can I make it a template?
Like this?

template <size_t sz>
constexpr void checksum_calc(std::array<char, sz>& arr)
{
  char x = 0;
  char y = 0;
  
  for (int i = 0; i < sz - 2; i++)
  {
      x = x + array[i];
      y = x + y;
  }
  arr[sz - 2] = x;
  arr[sz - 1] = y;
}

Example:

char * getData()
{
  // two extra bytes for the checksum
  static std::array<char, 12> numbers = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
  checksum_calc<12>(numbers);
  return &numbers[0];
}

The reason I chose a template is because I want arrays of different sizes like:

Example 2:

char * foo_getData()
{
  // two extra bytes for the checksum
  static std::array<char, 7> numbers = {1, 2, 3, 4, 5};
  checksum_calc<7>(numbers);
  return &numbers[0];
}

char * bar_getData()
{
  // two extra bytes for the checksum
  static std::array<char, 9> numbers = {1, 2, 3, 4, 5, 6, 7};
  checksum_calc<9>(numbers);
  return &numbers[0];
}

The purpose is to have a constant array followed by 2 bytes checksum that must be calculated.
I don't want to calculate it by hand and add it.

Is what I'm trying to do a good practice?

5
  • If your numbers array is constexpr, you can create another constexpr like numbers_with_chksumwith the checksum but you can't just change the size of a std::array after the fact whether constexpr or not. Commented Dec 27, 2022 at 17:00
  • Please clarify Your intent is to use static std::array<char, 12> numbers = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 0, 0}; or similar with 2 extra entries for the checksum in place of static std::array<char, 10> numbers = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};? Commented Dec 27, 2022 at 17:03
  • @doug Will I end up having only one array in the code at the end? Commented Dec 27, 2022 at 17:03
  • @user4581301 Yes, and calculate the checksum using a constexpr function at compile time. I want to populate the 2 last positions of the array at compile time, since all bytes are known. Can I do that? Commented Dec 27, 2022 at 17:06
  • Playing with compiler explorer shows that, yes, it will happen at compile time, see: godbolt.org/z/5M8znznxe There array was optimized out completly. BUT, its not a requirement for constexpr functions to be executed at compile time, they merely may be executed at compile time if they called not in constant expression, so in complex situations they can be executed at runtime. Commented Dec 27, 2022 at 17:26

2 Answers 2

1

Also, if you want to create constexpr arrays and have C++17 you can do following:

template <size_t sz>
constexpr std::array<char, sz+2> checksum_calc(const std::array<char, sz>& arr)
{
  std::array<char, sz+2> res = {};
  char x = 0;
  char y = 0;
  
  for (int i = 0; i < sz; i++)
  {
      res[i] = arr[i];
      x = x + arr[i];
      y = x + y;
  }
  res[sz] = x;
  res[sz+1] = y;
  return res;
}

And then use it like this:

constexpr array<char, 1> a1 = {1};
constexpr auto a2 = checksum_calc(a1);

//or

constexpr auto a3 = checksum_calc<1>({2});
Sign up to request clarification or add additional context in comments.

2 Comments

Will I end up having only one array at the end? Can the compiler optimize out the first array and leave me with the desired result? Because I wouldn't like spending memory and keep both arrays
Yes, it may even optimize out second array too, this depend on its usage.
1

Do you need checksum_calc to be separated? Otherwise, you can play more with C++17 capabilities and group your array and checksum compute together: https://godbolt.org/z/TW8EEG7Ej

template<typename _Ty, std::size_t _N>class checksumed_array {
  std::array<_Ty, _N + 2> _data;

  constexpr void compute_checksum() noexcept {
    char x = 0;
    char y = 0;

    for (int i = 0; i < _N; i++) {
      x = x + _data[i];
      y = x + y;
    }
    _data[_N] = x;
    _data[_N+1] = y;
  }
public:
  template<typename... _TyInt>
  constexpr checksumed_array(_TyInt... vals) noexcept : _data{ ((_Ty)vals)... } {
    compute_checksum();
  }

  constexpr const _Ty& operator[](std::size_t i) const noexcept {
    return _data[i];
  }

  constexpr operator const std::array<_Ty, _N + 2>& () const noexcept {
    return _data;
  }
};

Thanks to this, everything is static and can probably be better optimized away. Warning: operator[] and cast should be done without const context for this class to operate at runtime.

Use example :

constexpr checksumed_array<int, 3> ca = { 1, 2, 3 };
std::cout << ca[2] << " " << ca[3] << " " << ca[4] << "\n";

[Edit 1] Fixed missing const attributes for operator[] and cast... Thanks @doug from comments !

3 Comments

constexpr functions can be evaluated at runtime or compile time. Your example is runtime. OP asked for compile time. To force an attempt at compile time use: constexpr checksumed_array<int, 3> ca = { 1, 2, 3 }; It fails. Nice coding, btw. but you need to read up more on constexpr.
Thanks for pointing it out! I was only looking at disassembled output and as clang -O3 was able to optimize the code anyway I didn't see the mistake. Updated
Looks good to go.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.