定义新类型的内存

时间:2016-04-15 22:11:37

标签: c++ gcc memory

是否可以定义新类型的内存。例如,在某些嵌入式系统编译器中,您可以执行此操作:

__flash const char array[] = "This is memory in flash (not ram) so I can waste it!";

因此可能更疯狂并定义一种新型内存(比如说SD卡)。

我基本上要问是否可以定义SD卡是什么(如何访问其中的数据)然后在sd内存中声明一个变量。 (每当它看到一个写入它调用sd方法的地方,它看到一个读取它调用sd方法的地方):

class SDCard{
public:
  void write(void* data,size_t length);
  void* read(size_t length);
  void* memAlloc(size_t length);

};

__sd char myVar;  //Grabs an address in the sd card based on SDCard::memAlloc
myVar = 'A';  //Calls whatever I defined the sd card write operation as
char other = myVar;  //Calls whatever I defined the sd card read operation as

我正在使用gcc如果我可以做一些特别的事情(我几乎愿意修改编译器源以允许我这样做)。

这样的事情是可能的,但有一些问题:

struct Vol_t{   //Would represent an SD card an external RAM or any other memory
    void write(void* data,size_t len,size_t add) const{}
    void* read(size_t len,size_t add) const{}
};
template<Vol_t* sd, class Type,size_t address>
struct MemDef{  //Wrap your type with this (maybe add -> operator support later
    void operator=(Type&& data){
        sd->write(&data,sizeof(data),address);
    }
    operator Type&(){
        return *reinterpret_cast<Type*>(sd->read(sizeof(Type),address));
    }
};

Vol_t SD;  //Initialize our SD card
MemDef<&SD,int,0xdeadbeaf> sdVar;  //Declare an int variable on the SD card

int main(int argc,char** args){
    sdVar = 12;   //Writes to the SD card
    int local = sdVar;  //Reads from the SD card
    system("Pause");
}

这种方法存在问题:

  • 优化器必须执行每一次读/写操作---- 不能对以这种方式声明的变量进行任何优化。 (这是主要问题)
  • 它有点不雅(但确实可以完成工作)
  • 你必须指定要使用的内存地址(如果编译器能够以某种方式将所有这些都计算在之前编译并自动
  • 那将是非常棒的

所以也许我必须在gcc中添加一个关键字(如果是这种情况,请指出我正确的方向开始)。

编辑:此方法存在另一个问题。如果一个类型有一个指向另一个变量的指针,该变量将不会在SD卡上初始化(只有指针会)。

2 个答案:

答案 0 :(得分:8)

可能有两种情况:

  1. 硬件是这样的:一定范围的地址映射到SD卡,并且可以使用该范围内的正常存储器访问指令从SD卡写入/读取数据。使用常规指针。
  2. 需要使用特殊指令/功能来读/写SD卡。例如SDCard::read函数,它调用OS上的特殊函数(如果有的话)或中断指令。
  3. __flash是GCC扩展程序。它使用不同的指令访问内存,并在另一个段上查找static数据。但它不能单独使用C ++以这种方式推广。它也不能用于动态分配。

    第一种情况(地址范围)

    要使用常规指针向SD卡读取/写入数据,需要将它们标记为volatile。这样编译器就不会优化和读/写。 volatile表示可以从程序外部更改/使用内存,例如硬件将其写入SD卡。请参阅http://en.cppreference.com/w/cpp/language/cv

    例如

    volatile char* data = 0x00010000;
    memcpy(data, "test", 5);
    

    在SD卡上写"test",例如内存范围0x00010000 .. 0x0001ffff映射到它。

    要在SD卡上动态分配内存,例如mallocfree用于常规工作内存,则需要自定义分配器。它需要处理内存分段本身,即它需要映射存储器的哪些区域是空闲的或分配的,并且allocate(len)需要找到长度至少为len的空闲段。这通常由操作系统处理。

    这可以用C ++编写为 allocator 类,这个类必须满足Allocator(概念):http://en.cppreference.com/w/cpp/concept/Allocator的要求。例如(不完整):

    template<typename T>
    class SD_allocator {
        using value_type = T;
        using pointer = T*;
        pointer allocate(std::size_t len) {} // allocate segment of len bytes
        void deallocate(pointer, std::size_t) {}
    };
    

    如果可以与STL容器一起使用,例如:

    std::vector<int, SD_allocator<int>> vec;
    

    使用SD卡上的内存作为vec的项目。这里它们不是volatile,仅用于程序内部,而不是用于SD卡上的持久存储。

    C ++中的标准分配器是std::allocator,它分配常规内存,如mallocfree

    Boost似乎提供了一个在自定义内存区域上处理分段的分配器:

    http://www.boost.org/doc/libs/1_35_0/doc/html/interprocess/managed_memory_segments.html http://www.boost.org/doc/libs/1_55_0/doc/html/boost/interprocess/allocator.html

    对于持久存储,例如SD卡,最好为SD卡上的数据定义固定结构和布局,然后对其进行读/写。

    struct SDCard_data {
        std::int32_t int1;
        std::int32_t buffer1[500];
        std::int8_t padding_[34];
        int four_bit1 : 4;
        int four_bit2 : 4;
        bool bit1:1;
        bool bit2:1;
        bool bit3:1;
        bool bit4:1;
    };
    
    static volatile SDCard_data* sdcard
        = reinterpret_cast<volatile SDCard_data*>(0x0001000);
    
    int write_to_card() {
        // writes to the card
        card->int1 = 32;
        card->bit3 = true;
    }
    

    第二种情况(特别说明)

    如果对SD卡的读/写与硬件上的常规内存访问指令不对应,则无法使用原始volatile指针直接访问其上的数据。

    如果目标仍然是以这种方式访问​​它,则需要诸如MemDef之类的类。最好将SD卡视为文件/流,而是使用fopenfreadfprintf之类的功能将相应的整块数据写入/读取SD卡。类似。

    对象需要为此序列化/反序列化。将struct复制为原始内存,例如

    struct A;
    A a;
    write_to_card(reinterpret_cast<void*>(&a), sizeof(A))
    
    只要structPODType并且不包含任何指针/引用,

    就可以工作,即内部表示取决于内存地址的类型。它还取决于平台的内存布局(对齐,结构填充),字节顺序,floatCHAR_BIT的表示等。用于跨平台支持(例如,当从另一个读取SD卡时)使用另一个微控制器的设备,需要使用某种文件格式。

    定义自定义Allocator类也可能(但很难),该类使用类似MemDef的类作为指针类型。

答案 1 :(得分:2)

好吧,在C ++世界中,为了抽象内存通常你会编写一个自定义分配器。沿线

template <class T>
class SDAlloc {
 public:
   typedef T        value_type;
   typedef T*       pointer;
   typedef const T* const_pointer;
   typedef T&       reference;
   typedef const T& const_reference;
   typedef std::size_t    size_type;
   typedef std::ptrdiff_t difference_type;

   // rebind allocator to type U
   template <class U>
   struct rebind {
       typedef SDAlloc<U> other;
   };

   // return address of values
   pointer address (reference value) const {
       return &value;
   }
   const_pointer address (const_reference value) const {
       return &value;
   }

   SDAlloc(const char* device) {
       // open device by name
       // make helper structures
   }
   ~SDAlloc() {
       // close device
   }

   // return maximum number of elements that can be allocated
   size_type max_size () const throw() {
       return SDsize;
   }

   // allocate but don't initialize num elements of type T
   pointer allocate (size_type num, const void* = 0) {
       // print message and allocate memory on SD
   }

   .......