在程序存储器中为AVR构建编译时任意长度数组

时间:2017-09-30 15:29:31

标签: c++ c arrays avr-gcc

我正在尝试找出一种智能方法来为AVR架构构建复合编译时阵列。该数组的结构应如下:

  • 它应该完全驻留在程序存储器中;
  • 它由一系列连续的(无符号)字节组成,又名uint8_t;
  • 它应该使用任意长度的字节段构建;
  • 一个段按顺序包含一个长度字节和一系列数据字节,长度字节是数据字节数。

以下是此类数组的示例:

static const uint8_t data[] PROGMEM = {
    1, 0x01,
    3, 0xBE, 0x02, 0x00,
    3, 0x3D, 0x33, 0x33,
    15, 0xE1, 0xD0, 0x00, 0x05, 0x0D, 0x0C, 0x06, 0x2D, 0x44, 0x40, 0x0E, 0x1C, 0x18, 0x16, 0x19,
    0 /* end of the sequence */
};

我想避免每次在序列中添加或删除字节时调整长度字节的负担,例如,在某种形式的伪代码中:

BEGINNING_OF_THE_SEQUENCE(identifier)
    SEGMENT(0x01),
    SEGMENT(0xBE, 0x02, 0x00),
    ...
END_OF_THE_SEQUENCE()

在上面的例子中,我选择了一个显式字节数组声明,但它可以以任何方式构建,例如使用结构。唯一的先决条件是必须保证外观顺序。

所以简而言之,我想“连接”一系列字节,这些字节必须在编译时计算,并作为系列本身的长度字节放在每个字节序列的前面。

我考虑过使用variadic macros,但我也想研究其他方法,例如类和函数模板,元编程,诸如此类,并考虑到最小的代码。我也不想使用C ++ 11特有的,因为到目前为止我使用的当前avr-gcc编译器的支持是有限的。

我有预感可以使用模板,但我被卡住了。有什么想法吗?

3 个答案:

答案 0 :(得分:2)

以下是C ++ 11及更高版本的一个简单示例,可能有所帮助:

template <typename ...Args>
constexpr std::size_t n_args(Args...) { return sizeof...(Args); }

#define ELEM(...) n_args(__VA_ARGS__), __VA_ARGS__

#include <iostream>

int main()
{
    unsigned int a[] = { ELEM(4, 9, 16),
                         ELEM(100),
                         ELEM(10, 20, 30, 40, 50),
    };

    for (auto n : a ) std::cout << n << " ";
    std::cout << '\n';
}

或者,您可以使用sizeof复合字符数组文字代替n_args,如果您想要C99解决方案而不是C ++ 11解决方案:

#define ELEM(...) sizeof((char[]){__VA_ARGS__}), __VA_ARGS__

我不知道在C ++ 03中可以使用的类似简单方法。

答案 1 :(得分:0)

这是一种方法:

#include <stdint.h>
#include <stdio.h>
#define PROGMEM
#define _ARGSIZE(...) sizeof((uint8_t[]){__VA_ARGS__})/sizeof(uint8_t)
#define _SEGMENT(...)  _ARGSIZE( __VA_ARGS__ ), __VA_ARGS__
#define BEGINNING_OF_THE_SEQUENCE(__id)   uint8_t static const __id[] PROGMEM =  {
#define END_OF_THE_SEQUENCE() }

BEGINNING_OF_THE_SEQUENCE(data)
    _SEGMENT(0x01),
    _SEGMENT(0xBE, 0x02, 0x00),
    _SEGMENT(0xDE, 0xAD, 0xBE, 0xEF)
END_OF_THE_SEQUENCE();

int main() {
    int k, counter = data[0];
    for (k = 0; k < sizeof(data); k++) {
        fprintf(stderr, "%02x ", data[k]);
        if(counter-- == 0) {
            counter = data[1+k];
            fprintf(stderr, "\n");
        }
    }
}

这种方法与C99兼容。

上面的宏可以小心修改,以处理传递的任何类型的数据结构,而不是uint8_t(包括:结构中的P结构)

答案 2 :(得分:0)

无宏C ++ 11方法(v2):

#include <array>
#include <iostream>
#include <cstddef>
#include <cstdint>

//  This template will be instantiated repeatedly with VItems list
//  populated with new items.
template<typename TItem,  TItem... VItems> class
t_PackImpl
{
    //  This template will be selected for second and all other blocks.
    public: template<TItem... VInnerItems> using
    t_Pack = t_PackImpl
    <
        TItem
    //  add all previous items
    ,   VItems...
    //  add item holding amount of items in new block
    ,   TItem{static_cast<TItem>(sizeof...(VInnerItems))}
    //  add new block items
    ,   VInnerItems...
    >;

    //  This method will be called on the last instantiated
    //  template with VItems containing all the items.
    //  Returns array containing all the items with extra 0 item at the end.
    public: static constexpr auto
    to_array(void) -> ::std::array<TItem, sizeof...(VItems) + ::std::size_t{1}>
    {
        return {VItems..., TItem{}};
    }
};

//  This template will be instantiated just once.
//  Starts t_PackImpl instantiation chain.
template<typename TItem> class
t_BeginPack
{
    //  This template will be selected for first block.
    public: template<TItem... VInnerItems> using
    t_Pack = t_PackImpl
    <
        TItem
    //  add item holding amount of items in new block
    ,   TItem{static_cast<TItem>(sizeof...(VInnerItems))}
    //  add new block items
    ,   VInnerItems...
    >;
};

int main()
{
    {
        constexpr auto items
        {
            t_BeginPack<::std::uint8_t>::t_Pack<42>::to_array()
        };
        for(auto const & item: items)
        {
            ::std::cout << static_cast<::std::uint32_t>(item) << ::std::endl;
        }
    }
    ::std::cout << "----------------" << ::std::endl;
    {
        constexpr auto items
        {
            t_BeginPack<::std::uint8_t>::t_Pack<0, 1, 2>::to_array()
        };
        for(auto const & item: items)
        {
            ::std::cout << static_cast<::std::uint32_t>(item) << ::std::endl;
        }
    }
    ::std::cout << "----------------" << ::std::endl;
    {
        constexpr auto items
        {
            t_BeginPack<::std::uint8_t>::
                t_Pack<0, 1, 2>::
                t_Pack<0, 1>::
                t_Pack<0, 1, 2, 3, 4, 5>::to_array()
        };
        for(auto const & item: items)
        {
            ::std::cout << static_cast<::std::uint32_t>(item) << ::std::endl;
        }
    }
    return(0);
}

Run online