我正在玩一些 avr 微 Controller 和 C++14。在尝试为 io 引脚实现 C++ 包装器时,我偶然发现了一个错误。
我的想法是,让包装器将 sfr
作为模板参数,以便为编译器轻松优化(不需要额外的函数并使用我可以向编译器指示的模板参数,我的论点应该始终是编译时可评估的)。我想,可以有 constexpr uint8_t& x = ...
变量引用一些编译时已知地址。但以下内容不起作用(定义取自 avr includes):
#include <avr/io.h>
constexpr uint32_t addr[] = { _SFR_IO_ADDR(PORTB) };
constexpr uint32_t GetAddr()
{
return addr[0];
}
constexpr decltype(auto) Get()
{
_SFR_IO8(GetAddr());
}
int main() {
auto addr = GetAddr();
auto b = Get();
_SFR_IO8(addr) &= ~(1 << 2);
b |= (1 << 3);
}
它给我 error: expression '*(volatile uint8_t*)(GetAddr() + 32u)' has side-effects
在 Get()
函数中。将 decltype(auto)
替换为 uint8_t&
(当然)没有帮助。
为什么我无法获得指向内存位置的 constexpr uint8_t
引用 _SFR_IO_ADDR(PORTB) = (volatile uint8_t*)(_SFR_IO8(5u) - 32u) = (volatile uint8_t*)(5u + 32u - 32u)
?
最佳答案
我想要将类似的模板化编译时间简化为一条指令。我不得不使用一些模板元编程来完成这项工作。
一个精简的例子:
#include <avr/io.h>
struct A {
constexpr static volatile uint8_t *const PORT() { return &PORTA; }
constexpr static volatile uint8_t *const DDR() { return &DDRA; }
};
template <class port, u1 pin> class IOpin {
constexpr static volatile uint8_t *DDR = port::DDR();
constexpr static volatile uint8_t *PORT = port::PORT();
constexpr static uint8_t mask = 1 << pin;
public:
inline IOpin() {}
inline static void output() { *DDR |= mask; }
inline static void input() { *DDR &= ~mask; }
inline static void set() { *PORT |= mask; }
}
// Use as type or instance
using myPinType = IOpin<A, 1>;
IOpin<A, 1> myPinInstance;
// Use myPin
myPinType::set(true);
myPinInstance.output();
完整实现:https://github.com/cinderblock/AVR/blob/master/AVR%2B%2B/IOpin.hpp
关于c++ - 对 avr 端口地址的 constexpr 引用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41077173/