Ali
Ali

Reputation: 149

How to cast static const in the preprocessor (#if) to avoid overflow

I have a method overloaded to work efficiently with both uint8_t and uint16_t. (The code is written for 8bit AVR microcontroller).

In my code when the overloaded method is called, I want to use preprocessor #if to check which function should be called based on 2 static const variable that I have. If the multiplication of these two variable become less than 8 bit, I want to call the uint8_t and if not, I want to call the uint16_t. ( the two variables are TEXT_AREA and NUMBER_OF_ROWS)

After testing the code with the preprocessor, I noticed that the uint8_t version is always called. I think it is because of overflow in the #if condition (I may be wrong). So how can I fix this problem?

This is the snippets :

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

Upvotes: 1

Views: 619

Answers (2)

Caleth
Caleth

Reputation: 62939

Use templates and std::integral_constant, not the preprocessor.

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()>{});
    }
}

Upvotes: 1

if you use some symbol to be tested by some #if preprocessor directive, that symbol should be defined at preprocessing time (which happens before the actual parsing of your source file by the C++ compiler).

So you probably want to use

 #define HORIZONTAL_PIXELS 240

instead of

 static const uint8_t HORIZONTAL_PIXELS = 240;

If you really need such a const you could name it otherwise:

static const uint8_t k_HORIZONTAL_PIXELS = HORIZONTAL_PIXELS;

Read more about the C & C++ preprocessor. If you have a source file foo.cc try to get its preprocessed form with

g++ -C -E foo.cc > foo.ii

(perhaps adding other preprocessing flags like -I... or -D....) then look with a pager or an editor into the generated foo.ii

Upvotes: 2

Related Questions