我想创建一个管理Cortex-M3设备的位带功能的类。对于那些不知道的人:处理器将特定区域内的每一位映射到整个单词。这允许对特定位进行原子设置操作。该类本身与std :: uintptr_t一起使用。对于构造函数,我想允许一个任意指针,因为我不在乎它指向的是什么。它可能是设备头中定义的某些结构。

我当前的实现为构造函数提供了:

Bitband(uintptr_t address, uint32_t bitNumber);
Bitband(void * ptr, uint32_t bitNumber);


我的应用程序这样调用构造函数:

Bitband foo(reinterpret_cast<uintptr_t>(&gpioPort->IDR), pin);


如果我不考虑他的reinterpret_cast,则不会得到'uintptr_t'和'void *'的已知转换。
有没有一种干净的方法来消除每次调用的reinterpret_cast并采用任意指针作为构造函数的参数?

编辑:这是我当前的类Bitband的代码,以及我用来打开或关闭led的代码:

位带

#pragma once

#include <stdint.h>

class Bitband
{
public:
  Bitband(uintptr_t address, uint32_t bitNumber);
  Bitband(void * address, uint32_t bitNumber);

  inline void Set(bool val) const
  {
    uint32_t * const pData = reinterpret_cast<uint32_t *>(this->bbAddress);
    *pData = val;
  }

  inline bool Get() const
  {
    uint32_t * const pData = reinterpret_cast<uint32_t *>(this->bbAddress);
    return *pData;
  }
private:
  static uintptr_t GetBitBandAddress(uintptr_t address, uint32_t bit);
  static bool IsSramAddress(uintptr_t address);
  static bool IsPeripheralAddress(uintptr_t address);

  uintptr_t const bbAddress;

/* Constants for bit band calculation for SRAM */
  static uintptr_t const sramStartAddress = 0x20000000;
  static uintptr_t const sramEndAddress   = 0x200FFFFF;
  static uintptr_t const sramBbBaseAddress = 0x22000000;

/* Constants for bit band calculation for Peripherals */
  static uintptr_t const peripheralsStartAddress = 0x40000000;
  static uintptr_t const peripheralsEndAddress   = 0x400FFFFF;
  static uintptr_t const peripheralsBbBaseAddress = 0x42000000;
};


位带

#include "bitband.hpp"
#include <cassert>

Bitband::Bitband(uintptr_t address, uint32_t bitNumber) :
  bbAddress(GetBitBandAddress(address, bitNumber)) {}

Bitband::Bitband(void * address, uint32_t bitNumber) :
  bbAddress(GetBitBandAddress(reinterpret_cast<uintptr_t>(address), bitNumber)) {}

uintptr_t Bitband::GetBitBandAddress(uintptr_t const address,
                                      uint32_t const bitNumber)
{
  uintptr_t bbBase;
  uintptr_t regionStartAddress;

  assert(Bitband::IsPeripheralAddress(address)
          || Bitband::IsSramAddress(address));

  /* Set the parameters depending on wether we are in peripherals region or sram
    region. */
  if(Bitband::IsSramAddress(address))
  {
    bbBase = Bitband::sramBbBaseAddress;
    regionStartAddress = Bitband::sramStartAddress;
  }
  else if(Bitband::IsPeripheralAddress(address))
  {
    bbBase = Bitband::peripheralsBbBaseAddress;
    regionStartAddress = Bitband::peripheralsStartAddress;
  }
  else
  {
    /* Invalid parameter */
    __breakpoint(0);
  }

  uintptr_t byteOffset = address - regionStartAddress;
  auto bitWordOffset = (byteOffset * 32) + (bitNumber * sizeof(uint32_t));
  auto bitWordAddr = bbBase + bitWordOffset;

  return bitWordAddr;
}

bool Bitband::IsSramAddress(uintptr_t address)
{
  return (address >= Bitband::sramStartAddress)
            && (address <= Bitband::sramEndAddress);
}

bool Bitband::IsPeripheralAddress(uintptr_t address)
{
  return (address >= Bitband::peripheralsStartAddress)
            && (address <= Bitband::peripheralsEndAddress);
}


它由我的班级领导使用(对于测试,我只是打开/关闭了一些领导)

led.hpp

#pragma once

#include <stdint.h>
#include "stm32l1xx.h"                  // Keil::Device:Startup
#include "bitband.hpp"

class Led
{
public:
  Led(GPIO_TypeDef * const ledPort, uint16_t ledPin);
  inline void Set(bool newState) { this->ledOutputBitBand.Set(!newState); }
private:
  Bitband ledOutputBitBand;
};


led.cpp

#include <led.hpp>
#include <cassert>

Led::Led(GPIO_TypeDef * const port, uint16_t const pin) :
    ledOutputBitBand(reinterpret_cast<uintptr_t>(&port->ODR), pin)
{
  assert(pin < 16);

  /* Set port mode to push pull */
  port->MODER |= 1 << ( 2 * pin);
}


在主应用程序中使用

Led greenLed(GPIOD, 0);
greenLed.Set(true);


如果我省略了reinterpret_cast,则会收到以下消息:

Src/led.cpp(5): error: no matching constructor for initialization of 'Bitband'
    ledOutputBitBand(&port->ODR, pin)
    ^                ~~~~~~~~~~~~~~~

./Inc/bitband.hpp(9): note: candidate constructor not viable: no known conversion from 'volatile uint16_t *' (aka 'volatile unsigned short *') to 'uintptr_t' (aka 'unsigned int') for 1st argument; remove &
  Bitband(uintptr_t address, uint32_t bitNumber);
  ^

./Inc/bitband.hpp(10): note: candidate constructor not viable: no known conversion from 'volatile uint16_t *' (aka 'volatile unsigned short *') to 'void *' for 1st argument
  Bitband(void * address, uint32_t bitNumber);
  ^

./Inc/bitband.hpp(6): note: candidate constructor (the implicit copy constructor) not viable: requires 1 argument, but 2 were provided
class Bitband
      ^

./Inc/bitband.hpp(6): note: candidate constructor (the implicit move constructor) not viable: requires 1 argument, but 2 were provided
1 error generated.


所以我想,如果我想在另一个上下文中使用Bitband类,就不得不再次使用reinterpret_cast吗?

最佳答案

根据您提供的要求,这是干净的方法。

我不太了解您打算调用哪个构造函数(您没有明确说明目标),但是无论哪种方式,reinterpret_cast似乎都是最接近明智的。

它很冗长,以提醒您应该重新访问设计,并提出一个不需要此转换的设计。因为我们不再生活在1970年代。 :)

但是,如果您坚持使用旧样式,则可以改用C样式强制转换:

Bitband foo((void*)&gpioPort->IDR, pin);


我恳求你不要。

10-08 08:57