3

I'm trying to display an integer on an LCD-Display. The way the Lcd works is that you send an 8-Bit ASCII-Character to it and it displays the character.

The code I have so far is:

unsigned char text[17] = "ABCDEFGHIJKLMNOP";
int32_t n = 123456;
lcd.printInteger(text, n);

//-----------------------------------------  

void LCD::printInteger(unsigned char headLine[17], int32_t number)
{
    //......


    int8_t str[17];
    itoa(number,(char*)str,10);


    for(int i = 0; i < 16; i++)
    {
        if(str[i] == 0x0)
        break;

        this->sendCharacter(str[i]);
        _delay_ms(2);

    }
}
void LCD::sendCharacter(uint8_t character)
{
    //....

    *this->cOutputPort = character;

    //...

}

So if I try to display 123456 on the LCD, it actually displays -7616, which obviously is not the correct integer.

I know that there is probably a problem because I convert the characters to signed int8_t and then output them as unsigned uint8_t. But I have to output them in unsigned format. I don't know how I can convert the int32_t input integer to an ASCII uint8_t-String.

Bobface
  • 2,782
  • 4
  • 24
  • 61
  • There is also a question of your char* being signed or unsigned. The fact that you have to do the conversion inside `itoa` suggests unsigned. – SergeyA Jan 13 '16 at 15:48
  • Real ASCII is seven-bit, definitely including the digits — how you choose to interpret the most significant/sign bit should have no effect. So the cast shouldn't be problematic. Just a syntactic pain. – Tommy Jan 13 '16 at 15:51

1 Answers1

6

On your architecture, int is an int16_t, not int32_t. Thus, itoa treats 123456 as -7616, because:

123456 = 0x0001_E240
 -7616 = 0xFFFF_E240

They are the same if you truncate them down to 16 bits - so that's what your code is doing. Instead of using itoa, you have following options:

  1. calculate the ASCII representation yourself;
  2. use ltoa(long value, char * buffer, int radix), if available, or
  3. leverage s[n]printf if available.

For the last option you can use the following, "mostly" portable code:

void LCD::printInteger(unsigned char headLine[17], int32_t number) {
  ...
  char str[17];
  if (sizeof(int) == sizeof(int32_t))
    snprintf(str, sizeof(str), "%d", num);
  else if (sizeof(long int) == sizeof(int32_t))
    snprintf(str, sizeof(str), "%ld", num);
  else if (sizeof(long long int) == sizeof(int32_t))
    snprintf(str, sizeof(str), "%lld", num);
  ...
}

If, and only if, your platform doesn't have snprintf, you can use sprintf and remove the 2nd argument (sizeof(str)). Your go-to function should always be the n variant, as it gives you one less bullet to shoot your foot with :)

Since you're compiling with a C++ compiler that is, I assume, at least half-decent, the above should do "the right thing" in a portable way, without emitting all the unnecessary code. The test conditions passed to if are compile-time constant expressions. Even some fairly old C compilers could deal with such properly.

Nitpick: Don't use int8_t where a char would do. itoa, s[n]printf, etc. expect char buffers, not int8_t buffers.

Kuba hasn't forgotten Monica
  • 95,931
  • 16
  • 151
  • 313
  • 3
    Can I borrow your crystal ball, please? – SergeyA Jan 13 '16 at 15:49
  • ... couldn't he likely just use `sprintf` (or, ideally, `snprintf`) with an `ll` specifier? Without knowing the compiler and whether it equates a long long with being 32-bit, of course. – Tommy Jan 13 '16 at 15:50
  • 1
    you really need to make that crystal-ball technology of yours publicly available ... – specializt Jan 13 '16 at 16:16
  • It was the first thing I thought of. I think that this is representative of typical problems you get with languages that let you truncate integers by default and compilers that don't warn you of the fact. C could have enforced an explicit narrowing cast, but it doesn't, and such bugs are the result. The worst part: this behavior makes default types such as `int` virtually useless. Portable code needs to use integer types from `` exclusively (and char where needed for library APIs). – Kuba hasn't forgotten Monica Jan 13 '16 at 16:22