如何在预处理器(#if)中转换静态const以避免溢出

时间:2017-05-26 07:48:56

标签: c++ casting constants preprocessor

我有一个方法重载,以便与uint8_t和uint16_t一起高效工作。 (代码是为8位AVR微控制器编写的。)

在我的代码中调用重载方法时,我想使用预处理器#if来检查应该根据我拥有的2个静态const变量调用哪个函数。如果这两个变量的乘法变得小于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;   
}
}

2 个答案:

答案 0 :(得分:2)

如果使用某些符号通过某个#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

答案 1 :(得分:1)

使用模板和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()>{});
    }
}