是否可以在C ++中将任意指针作为输入参数?

时间:2017-01-03 01:28:22

标签: c++

我想创建一个管理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的代码:

bitband.hpp

#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;
};

bitband.cpp

#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)

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吗?

1 个答案:

答案 0 :(得分:3)

鉴于您提供的要求,干净的方式。

我真的不明白你打算打电话给哪个构造函数(你没有明确指出你的目标)但无论如何,reinterpret_cast似乎最接近合情合理。

为了提醒您应该重新审视您的设计,并且首先想出一个不需要这种转换的设计,这很冗长。因为我们不再生活在20世纪70年代。 :)

但是,如果你坚持旧样式,你可以改为使用C风格的演员:

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

我恳请你不要。