2017-01-03 54 views
0

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

我目前的实现提供了构造具有:

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.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); 
} 

它使用我的类主导(在TE STS我只要打开/关闭一些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. 

所以我想,如果我想使用类位段在另一个方面,我不得不再次使用reinterpret_cast的?

+0

将'&gpioPort-> IDR'转换为'void *'(除非'IDR'为'const')应该没有问题。请复制并粘贴整个错误消息以及导致它的代码。 – molbdnilo

+0

我还没有试过这个,但是如果你让构造函数成为一个模板,它接受一个指向模板类型的指针,然后在构造函数本身中进行reinterpret强制转换,会发生什么?如果实际上使用不同的指针类型调用构造函数,这可能最终会放大代码(如果它没有被优化),但它可能会使您的调用看起来更清晰。或者,您可以考虑使用宏来缩短重新演绎演员的朗诵。 –

回答

3

鉴于您提供的要求,该干净的方式来做到这一点。

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

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

如果你坚持要老的款式,不过,你也可以使用C风格的转换:

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

我恳求你不要。

相关问题