Arduino int to string: How to convert an integer to a string. Find out the standard form and Learn how to code it yourself. Also find the one subtle error you missed.


Arduino int to string - find out:
  • The standard function for int to string conversion.
  • The algorithm used to do the conversion.

  • Exactly how to code it yourself.

  • A subtle hidden error in some external code.

How to use the itoa function to convert an integer into a string.

If you want to know how it really does its magic, this page will also show you fundamental code for Arduino int to strings conversion .

Standard form of Arduino int to string

The function you need is itoa() which has the prototype:

    char *itoa( int value, char *str, int base);

Where:

  • value     - is the integer you want to change to a string.
  • str         - is a string buffer that stores the string.
  • base      - is the conversion radix.

The function takes the above arguments and returns a string (it is basically the same string buffer that you gave it!).

You supply the integer value, a pointer to buffer that will store the string 'str' and then specify the base which can be any number, but common ones are:

  •     10 for decimal,
  •     16 for hexadecimal,
  •     2 for binary

The base can be any integer - but you'll get odd characters above 36 - and eventually run out of characters!

The name of the function is an acronym for int to ASCII - itoa.

Where ASCII is another acronym standing for American Standard Code for Information Interchange. It defines is a table of characters.

String Buffer length

The string buffer must allow room for the maximum characters that can be created when converting an integer.

Warning: Allow for the maximum string output in your buffer.

If you don't you could overwrite other variables causing random output!

For example a decimal string requires 5 characters,  space for a minus sign, and a null termination '\0'. So a buffer of length 7.

Hexadecimal requires 4 characters and a null termination '\0'.

Binary requires 16 characters and a null termination '\0'.

Simple Arduino int to string example

static char buf[17];

char *convertBin( int v ) {

   return itoa(v, buf, 2);

}

Fundamental Code: Arduino int to string conversion

Introduction

How to code itoa from first principles.

For the Arduino Uno, integers are defined as 16 bits long. The C standard does not specify the length of an integer so for a different chip e.g. a 32 bit processor such as the ESP32, an integer could have a different length (probably 32 bits!).

If you really want to tie down the compiler use the type below:

    int16_t <variable name>;

which (for the Uno) is the same as:

    int <variable name>;

Both of the above are signed integers that use the two's complement representation of binary numbers.

It is important to know the length (in bits) of the integer since that determines the maximum possible string length. That means you can set the minimum required string buffer length in your code. So for an integer, the range is:

    -32768  ~ +32767

If this was an unsigned integer then the range would be:

    0 ~ 65535         = pow(2,16)-1;

So for a signed integer, the maximum string length buffer required is 6 characters (including minus sign). Unsigned requires 5 characters.

The maximum buffer length for both signed and unsigned integers is 7 characters (including the null string terminator).

Arduino int to string Algorithm

Now you have the fundamental information on the input and output variables you can start to write the algorithm.

Storage:

uint16_t v
char buf[7];

First of all determine the sign and store that information

    if (v<0) {
        sign = 1;
        v = -v;
    }

Also normalize the number so you are working only with positive integers.

Since we use base 10 numbers the number we process will be divided by 10 each time around a loop - the remainder is the bit we store in the buffer.

So lets say we have a number 12345 to convert into a string.

Repeat an integer division and store the remainder:

Maths
Result
Buffer content
12345/10 = 1234 remainder 5
buf[1] = 5
1234/10
= 123 remainder 4
buf[2] = 4
123/10 = 12 remainder 3
buf[3] = 3
12/10 = 1 remainder 2
buf[4] = 2
1/10 = 0 remainder 1
buf[5] = 1
0: Terminate
null terminate the string
buf[6] = '\0'

As you can see, the buffer content is reversed, so to finalise the result you have to reverse the buffer content, remembering to add the sign character if needed.  

To get the remainder use the c expression '%'.

Arduino int to string Code

//****************************************************
// Find more Arduino Projects and Tutorials at TronicsBench.com
//
// Written by John Main.
//
// MIT license, all text above must be included in any redistribution
// ****************************************************

char *dectoa(int16_t v , char *str) {
char *p = str, *buf=str;
char ch;
byte sign = 0;

   // Special case if input is zero - display a zero!
   if (v==0) {
      str[0] = '0';
      str[1] = '\0';
      return str;
   }

  // // This commented-out code has a subtle problem
  //  if (v < 0)
  //       sign = 1;
  //       v = -v;
  //  }

  //  while (v) { // Number is not zero.
  //     *str++ = v % 10 + '0'; // zero = ascii '0'
  //     v /= 10;
  //  }

   if (v < 0)
        sign = 1;

   while (v) { // Number is not zero.
      *str++ =abs(v % 10) + '0'; // zero = ascii '0'
      v /= 10;
   }

   // Add the sign character if needed.
   if (sign)
      *str++ = '-';

   *str='\0';

   // Now reverse the string
   str--; // at last character.

   while(p < str) { // stop at middle or past middle.
      ch = *p;  // temporary store.
      *p = *str;
      *str = ch;
      p++; str--;
   }
   return buf;
}

void showValBuf(int v,char *buf) {
  Serial.print("Input variable v is: ");
  Serial.println(v);
  Serial.print("String buffer is ");
  Serial.println(buf);
  Serial.println("~~~~");
}

void setup() {
static char buf[7];

  Serial.begin(115200);
  Serial.println("Dec to A");

  int v = 12345;
  dectoa(v,buf);
  showValBuf(v,buf);

  v = 102;
  dectoa(v,buf);
  showValBuf(v,buf);

  v = 0;
  dectoa(v,buf);
  showValBuf(v,buf);

  v = -4783;
   dectoa(v,buf);
  showValBuf(v,buf);

  v = INT16_MAX;
  dectoa(v,buf);
  showValBuf(v,buf);

  v = INT16_MIN; 
  dectoa(v,buf);
  showValBuf(v,buf);

  v = 40000;
  dectoa(v,buf);
  showValBuf(v,buf);

}

void loop() {
  // put your main code here, to run repeatedly:

}

Ouptut from the code

 
Dec to A
Input variable v is: 12345
String buffer is 12345
~~~~
Input variable v is: 102
String buffer is 102
~~~~
Input variable v is: 0
String buffer is 0
~~~~
Input variable v is: -4783
String buffer is -4783
~~~~
Input variable v is: 32767
String buffer is 32767
~~~~
Input variable v is: -32768
String buffer is -32768
~~~~
Input variable v is: -25536
String buffer is -25536
~~~~

Note how the integer value 40000 is interpreted as a signed integer of value -25536.

A gotcha: Arduino int to string

I had a bit of trouble with this one and its useful for you to see how subtle problems can arise in any code.

I originally wrote that code as follows (commented out in above code):


   if (v<0) {
        sign = 1;
        v = -v;
   }

   while (v) { // Number is not zero.
      *str++ = v % 10 + '0'; // zero = ascii '0'
      v /= 10;
   }

Which has the intention of detecting a negative number and normalising it to a positive one, so that only positive values are used in the while loop. It means that the index into the ASCII array is positive and depends on the positive remainder value.

This all sounds very reasonable until you actually test it!

All reasonable numbers work fine. But testing an unreasonable number at the limits of the signed integer type shows a problem:


Normal numbers are fine:
~~~~
Input variable v is: 12345
String buffer is 12345
~~~~
Input variable v is: -4783
String buffer is -4783
~~~~

All looks good...

...but

dectoa(INT16_MAX,buf) & dectoa(INT16_MIN,buf) gives:


~~~~
Input variable v is: 32767
String buffer is 32767
~~~~
Input variable v is: -32768
String buffer is --.)*(
~~~~

It outputs garbage even though the code is entirely reasonable!

Note: These type of bugs are the hardest to find and correct.

This type of problem takes a while to sort out because the code is actually correct!

The problem is an underlying assumption about the system.

First you have to identify the problem which involves writing lots of Serial.print outputs and this lets you narrow down where the problem is located.

In this case the index value into the array was negative!

So looking at the specific case of INT16_MIN and printing the hex output helps.

    INT16_MIN = 0x8000;

Performing a two's complement for negating the value gives:

    complement: 0x7fff
    add one :0x8000

    Input : 0x8000     (or -32768)
    output : 0x8000   (or -32768)

So in the C code when writing...

    v = -v

...has no effect and does not make the value positive!

This is due to the operation of the two's complement addition.

Here v = -v results in the same negative number as -32768 can not be represented as a positive value! therefore the index into the ASCII table is negative which is why garbage is output.

How to solve it

Since the % operator can work with negative values the solution is to 'not' negate the variable v in the sign detection condition, and instead use the abs function on the smaller index values i.e.


Instead of :
   
    *str++ = v % 10 + '0'; // zero = ascii '0'

you use:

    *str++ =abs(v % 10) + '0'; // zero = ascii '0'

Note: This shows the importance of code testing and understanding of underlying operations.

Note: You can find the same error here:
https://www.geeksforgeeks.org/implement-itoa/

Full code with base control

The following code adds the ability to control the conversion radix (or base). It gives you the same operation as the commonly used itoa function.

It means you can output a number in any base e.g. hexadecimal is base 16, binary is base 2.

Note however that leading zeros are not output, and you must allow the string buffer more room i.e. for a binary output there are a possible 16 characters!


//****************************************************
// Find more Arduino Projects and Tutorials at TronicsBench.com
//
// Written by John Main.
//
// MIT license, all text above must be included in any redistribution
// ****************************************************

char *_itoa(int16_t v , char *str, int base) {

char *p = str, *buf=str;
char ch;
byte sign = 0;

   // Special case if input is zero
   if (v==0) {
      str[0] = '0';
      str[1] = '\0';
      return str;
   }

    if (v < 0 && base==10) // sign for decimal only.
        sign = 1; 

   while (v) { // Number is not zero.

      int rem = abs(v % base);

      // Set index into ASCII - numbers over 9 start from 'A'
      ch = '0';
      if (rem>9) {
         rem -=10;
         ch = 'A';
      }

      *str++ = rem + ch; // zero = ascii '0'

      v /= base;
   }

   // Add the sign character if needed.
   if (sign)
      *str++ = '-';

   *str='\0';

   // Now reverse the string
   str--; // at last character.

   while(p < str) { // Stop at middle or past middle.
      ch = *p;  // temporary store.
      *p = *str;
      *str = ch;
      p++; str--;
   }
   return buf;
}

void showValBuf(int v,char *buf) {
  Serial.print("Input variable v is: ");
  Serial.println(v);
  Serial.print("String buffer is ");
  Serial.println(buf);
  Serial.println("~~~~");
}

void setup() {
int v;
char buf[27];

  Serial.begin(115200);
  Serial.println("Dec to A");
 

  v = 12345;
  _itoa(v,buf,10);
  showValBuf(v,buf);

  v = INT16_MIN;
  _itoa(v,buf,10);
  showValBuf(v,buf);
  _itoa(v,buf,16);
  showValBuf(v,buf);

  v = INT16_MAX;
  _itoa(v,buf,10);
  showValBuf(v,buf);

  _itoa(v,buf,16);
  showValBuf(v,buf);

  v = 0x7ffe;
  _itoa(v,buf,16);
  showValBuf(v,buf);

  v = 102;
  _itoa(v,buf,10);
  showValBuf(v,buf);

  v = 0;
  _itoa(v,buf,10);
  showValBuf(v,buf);

  v = -4783;
  _itoa(v,buf,10);
  showValBuf(v,buf);

  v = 40000;
  _itoa(v,buf,10);
  showValBuf(v,buf);

  v = 0xff;
  _itoa(v,buf,2);
  showValBuf(v,buf);

  v = 0x5a;
  _itoa(v,buf,2);
  showValBuf(v,buf);

}

void loop() {
  // put your main code here, to run repeatedly:

}

Output from above code

 
Input variable v is: 12345
String buffer is 12345
~~~~
Input variable v is: -32768
String buffer is -32768
~~~~
Input variable v is: -32768
String buffer is 8000
~~~~
Input variable v is: 32767
String buffer is 32767
~~~~
Input variable v is: 32767
String buffer is 7FFF
~~~~
Input variable v is: 32766
String buffer is 7FFE
~~~~
Input variable v is: 102
String buffer is 102
~~~~
Input variable v is: 0
String buffer is 0
~~~~
Input variable v is: -4783
String buffer is -4783
~~~~
Input variable v is: -25536
String buffer is -25536
~~~~
Input variable v is: 255
String buffer is 11111111
~~~~
Input variable v is: 90
String buffer is 1011010
~~~~

Conclusions

The built in version works as expected; You can obtain a string version of an integer translated using any radix (number base).

Remember to allow enough characters in the buffer string to accept the maximum conversion length - which varies depending on the radix!

TIP: Make sure the buffer is long enough or risk run time errors.

You have learned, from this page, how to code the Arduino int to string function - itoa - from first principles.

If you code it yourself there are unexpected subtle problems (explored above) that are not to easy to solve or debug. They are solved above and give you a good idea of what it takes to figure out code/hardware.






Comments

Have your say about what you just read! Leave me a comment in the box below.

Don’t see the comments box? Log in to your Facebook account, give Facebook consent, then return to this page and refresh it.



Privacy Policy | Contact | About Me

Site Map | Terms of Use