如何在预处理器 (#if) 中转换 static const 以避免溢出
How to cast static const in the preprocessor (#if) to avoid overflow
我有一个重载的方法可以有效地与 uint8_t 和 uint16_t 一起工作。 (代码是为8bit AVR单片机写的)
在调用重载方法时的代码中,我想使用预处理器 #if 来检查应该根据我拥有的 2 个静态常量变量调用哪个函数。如果这两个变量的乘积小于 8 位,我想调用 uint8_t,如果不是,我想调用 uint16_t。 (这两个变量是TEXT_AREA和NUMBER_OF_ROWS)
用预处理器测试代码后,我注意到总是调用 uint8_t 版本。我认为这是因为#if 条件溢出(我可能错了)。那么我该如何解决这个问题呢?
这是片段:
static const uint8_t HORIZONTAL_PIXELS = 240;
static const uint8_t VERTICAL_PIXELS = 64;
static const uint8_t FONT_WIDTH = 6;
static const uint16_t TEXT_HOME_ADDRESS = 0x0200;
static const uint8_t TEXT_AREA = HORIZONTAL_PIXELS / FONT_WIDTH;
static const uint8_t NUMBER_OF_ROWS = VERTICAL_PIXELS / 8;
uint8_t GLCD_T6963C::clearTextMemory(void)
{
if( setAddressPointer(TEXT_HOME_ADDRESS) )
{
#if TEXT_AREA * NUMBER_OF_ROWS <= 255
Serial.println("I am uint8_t");
Serial.println(TEXT_AREA * NUMBER_OF_ROWS);
if( autoWriteConstantValue( (uint8_t) 0, (uint8_t) (TEXT_AREA * NUMBER_OF_ROWS) ) )
{
return 1;
}
else
{
return 0;
}
#endif
#if TEXT_AREA * NUMBER_OF_ROWS > 255
Serial.println("I am uint16_t");
if( autoWriteConstantValue( (uint8_t) 0, (uint16_t) (TEXT_AREA * NUMBER_OF_ROWS) ) )
{
return 1;
}
else
{
return 0;
}
#endif
}
else
{
return 0;
}
}
如果您使用某些符号来通过某些 #if
预处理器指令进行测试,则应在预处理时定义该符号(发生在 C++ 编译器实际解析您的源文件之前)。
所以你可能想使用
#define HORIZONTAL_PIXELS 240
而不是
static const uint8_t HORIZONTAL_PIXELS = 240;
如果你真的需要这样一个 const
你可以用其他方式命名它:
static const uint8_t k_HORIZONTAL_PIXELS = HORIZONTAL_PIXELS;
阅读有关 C & C++ preprocessor 的更多信息。如果您有源文件 foo.cc
尝试使用
获取其预处理形式
g++ -C -E foo.cc > foo.ii
(也许添加其他 preprocessing flags,如 -I
... 或 -D
...)然后使用寻呼机或编辑器查看生成的 foo.ii
使用模板和 std::integral_constant,而不是预处理器。
using HORIZONTAL_PIXELS = std::integral_constant<int, 240>;
using VERTICAL_PIXELS = std::integral_constant<int, 64>;
using FONT_WIDTH = std::integral_constant<int, 6>;
using TEXT_AREA = std::integral_constant<int, HORIZONTAL_PIXELS::value / FONT_WIDTH::value>;
using NUMBER_OF_ROWS = std::integral_constant<int, VERTICAL_PIXELS::value / 8>;
namespace detail {
uint8_t clearTextMemoryImpl(std::true_type) // type alias for std::integral_constant<bool, true>
{
// uint8_t case
Serial.println("I am uint8_t");
Serial.println(TEXT_AREA::value * NUMBER_OF_ROWS::value);
if( autoWriteConstantValue( (uint8_t) 0, (uint8_t) (TEXT_AREA::value * NUMBER_OF_ROWS::value) ) )
{
return 1;
}
else
{
return 0;
}
}
uint8_t clearTextMemoryImpl(std::false_type) // type alias for std::integral_constant<bool, false>
{
// uint16_t case
Serial.println("I am uint16_t");
if( autoWriteConstantValue( (uint8_t) 0, (uint16_t) (TEXT_AREA::value * NUMBER_OF_ROWS::value) ) )
{
return 1;
}
else
{
return 0;
}
}
}
uint8_t GLCD_T6963C::clearTextMemory(void)
{
if( setAddressPointer(TEXT_HOME_ADDRESS) )
{
// Choose overload based on compile-time computation
return detail::clearTextMemoryImpl(std::integral_constant<bool, TEXT_AREA::value * NUMBER_OF_ROWS::value <= std::numeric_limits<uint8_t>::max()>{});
}
}
我有一个重载的方法可以有效地与 uint8_t 和 uint16_t 一起工作。 (代码是为8bit AVR单片机写的)
在调用重载方法时的代码中,我想使用预处理器 #if 来检查应该根据我拥有的 2 个静态常量变量调用哪个函数。如果这两个变量的乘积小于 8 位,我想调用 uint8_t,如果不是,我想调用 uint16_t。 (这两个变量是TEXT_AREA和NUMBER_OF_ROWS)
用预处理器测试代码后,我注意到总是调用 uint8_t 版本。我认为这是因为#if 条件溢出(我可能错了)。那么我该如何解决这个问题呢?
这是片段:
static const uint8_t HORIZONTAL_PIXELS = 240;
static const uint8_t VERTICAL_PIXELS = 64;
static const uint8_t FONT_WIDTH = 6;
static const uint16_t TEXT_HOME_ADDRESS = 0x0200;
static const uint8_t TEXT_AREA = HORIZONTAL_PIXELS / FONT_WIDTH;
static const uint8_t NUMBER_OF_ROWS = VERTICAL_PIXELS / 8;
uint8_t GLCD_T6963C::clearTextMemory(void)
{
if( setAddressPointer(TEXT_HOME_ADDRESS) )
{
#if TEXT_AREA * NUMBER_OF_ROWS <= 255
Serial.println("I am uint8_t");
Serial.println(TEXT_AREA * NUMBER_OF_ROWS);
if( autoWriteConstantValue( (uint8_t) 0, (uint8_t) (TEXT_AREA * NUMBER_OF_ROWS) ) )
{
return 1;
}
else
{
return 0;
}
#endif
#if TEXT_AREA * NUMBER_OF_ROWS > 255
Serial.println("I am uint16_t");
if( autoWriteConstantValue( (uint8_t) 0, (uint16_t) (TEXT_AREA * NUMBER_OF_ROWS) ) )
{
return 1;
}
else
{
return 0;
}
#endif
}
else
{
return 0;
}
}
如果您使用某些符号来通过某些 #if
预处理器指令进行测试,则应在预处理时定义该符号(发生在 C++ 编译器实际解析您的源文件之前)。
所以你可能想使用
#define HORIZONTAL_PIXELS 240
而不是
static const uint8_t HORIZONTAL_PIXELS = 240;
如果你真的需要这样一个 const
你可以用其他方式命名它:
static const uint8_t k_HORIZONTAL_PIXELS = HORIZONTAL_PIXELS;
阅读有关 C & C++ preprocessor 的更多信息。如果您有源文件 foo.cc
尝试使用
g++ -C -E foo.cc > foo.ii
(也许添加其他 preprocessing flags,如 -I
... 或 -D
...)然后使用寻呼机或编辑器查看生成的 foo.ii
使用模板和 std::integral_constant,而不是预处理器。
using HORIZONTAL_PIXELS = std::integral_constant<int, 240>;
using VERTICAL_PIXELS = std::integral_constant<int, 64>;
using FONT_WIDTH = std::integral_constant<int, 6>;
using TEXT_AREA = std::integral_constant<int, HORIZONTAL_PIXELS::value / FONT_WIDTH::value>;
using NUMBER_OF_ROWS = std::integral_constant<int, VERTICAL_PIXELS::value / 8>;
namespace detail {
uint8_t clearTextMemoryImpl(std::true_type) // type alias for std::integral_constant<bool, true>
{
// uint8_t case
Serial.println("I am uint8_t");
Serial.println(TEXT_AREA::value * NUMBER_OF_ROWS::value);
if( autoWriteConstantValue( (uint8_t) 0, (uint8_t) (TEXT_AREA::value * NUMBER_OF_ROWS::value) ) )
{
return 1;
}
else
{
return 0;
}
}
uint8_t clearTextMemoryImpl(std::false_type) // type alias for std::integral_constant<bool, false>
{
// uint16_t case
Serial.println("I am uint16_t");
if( autoWriteConstantValue( (uint8_t) 0, (uint16_t) (TEXT_AREA::value * NUMBER_OF_ROWS::value) ) )
{
return 1;
}
else
{
return 0;
}
}
}
uint8_t GLCD_T6963C::clearTextMemory(void)
{
if( setAddressPointer(TEXT_HOME_ADDRESS) )
{
// Choose overload based on compile-time computation
return detail::clearTextMemoryImpl(std::integral_constant<bool, TEXT_AREA::value * NUMBER_OF_ROWS::value <= std::numeric_limits<uint8_t>::max()>{});
}
}