Arduino Float to String: Find out how to do it Easily. Is there a simple function that does this for you? What is the one thing you must do to ensure your program is reliable?: Find out here.

Arduino Float to String:
• Use the dtostrf function to convert a float into a string.

• Beware of the one big problem with dtostrf.

• Find out exactly how dtosrtf works here.

Turning a floating point number into a string is not an easy task, since a floating point number is represented in binary with a mantissa (digits part) and exponent (power multiplier). You need some fairly complex code to perform floating point mathematics so the easiest way is to use a pre-defined function.

Arduino floating point numbers are usually represented using 32bits when you use 8 bit processors; This is variable of type 'float' . For example Uno and Nano use 32bits. When you use a 32bit processor you'll probably get 64 bits (this is type 'double').

You can easily find how much memory your processor uses with this code:

void setup(void) {
Serial.begin(115200);
Serial.print("size of double: %d\n");
Serial.println(sizeof(double));
Serial.print("size of float: %d\n");
Serial.println(sizeof(float));
}

void loop() {}

Note: 'double' allows higher accuracy floating point v.s. 'float'. But 8 bit processors only implement 32bit 'float'.

For an Arduino Uno both values will be 4 i.e. 32bits for 'float' or 'double'. For an ESP32 or Arduino Due, you'll get 4 and 8. Indicating single and double precision are available i.e. 32bit or 64bit.

Arduino Float to String: Conversion Function - dtostrf

Knowing that type 'double' exists, explains the following function name:

dtostrf - Double To String Function.

When you want to turn an Arduino float to string, this is the function that you use. The function actually accepts a value of type 'double' but, since Arduino code treats 'double' as 'float' it also converts numbers of type 'float' into strings. Type 'double' is not implemented for Arduino 8 bit processor boards.

The prototype of dtostrf is:

char *dtostrf (double value, signed char width, unsigned char prec, char *buffer)

 Parameters for dtostrf dtostrf usage value The floating point value to be converted into a string. width Defines the minimum space for output including possible decimal and sign. prec The number of places displayed after the decimal point. buf The character buffer to store the converted float value. Return The function returns a char pointer to the string buffer.

Warning: Allow enough string space for any possible output string.

Arduino Float to String: Simple use

If you use dtostrf for small numbers there are no unexpected surprises:

void setup() {
char buf[6];

Serial.begin(115200);

float v = 1.23;
dtostrf(v,5,2,buf);
Serial.print(buf);
Serial.println("<")  ;
}

void loop() {

}

Here the output is:

1.23<

The left arrow shows the end of the string so it occupies 4 characters - remember to allow for zero string terminator and possible sign output - a total of 6 bytes.

Note that a larger value (v), with more digits to the left of the decimal point, will generate more output characters in the buffer, so make sure the buffer is large enough for your largest input value.

Arduino Float to String: Unexpected result

One thing you might not expect is that when you write a variable in scientific notation the string output function outputs a real value. it will expand the scientific notation into its real number equivalent! There is no convenient scientific notation so very large or very small numbers will output long strings!

For instance for the following scientific notation values you will get the expanded output shown:

float v = 1.2345e17; // Code for this output: dtostrf(v,20,2,buf);

String output will be : 123450000000000000.00 [ 21 characters ]

Note: dtostrf does NOT care about the size of the buffer or the value of width - it will output characters until it is finished!

float v= 1.2345e-12; // Code for this output: dtostrf(v,20,2,buf);

String output will be : 0.00

Note: In this case the precision parameter does limit the output string length generated.

To get a string output that means something for that value (v) use the following code: dtostrf(v,20,17,buf):

String output will be : 0.00000000000123450 [19 characters ]

Warning: Allow enough string space for any possible output string.
Warning: The output string length depends on the float value! and the precision specified.

Arduino Float to String: Example dtostrf Sketch

The following program changes the width parameter (from 0 to 19) while converting the floating point number 1.2345e12 to a string.

void setup() {
char buf[12];

Serial.begin(115200);

float v = 1.2345e12F;

for (int i=0;i<20;i++) {
dtostrf(v,i,2,buf);
Serial.print("buf :");
Serial.print(buf);
Serial.print("<");
Serial.println(i);
}
}

void loop() {
}

One thing that you might be interested in, is:

Why does the specification for dtostrf use the words minimum for the width parameter?

The following program shows what happens for changing that minimum - effectively it adds leading spaces to fullfill the width specified. However it only adds leading spaces if its output is less than the width. Look at the 1st 16 values - you can see that dtostrf outputs the string regardless of the width parameter. It means dtostrf outputs whatever it wants to generate the output string.

Warning: dtostrf output is not limited by the width parameter.

This is the reason that using this function could be a problem and cause memory leaks - you can unwittingly overwrite the next variable in memory as there is potentially no limit to the output string length! In actual fact there is a limit (3.4028235E+38 - you the maximum value of a float) so 1.2345e39F  triggers the limit - so you can get 38 characters in the buffer +4 (sign etc.). The limit is bigger for 64 bit doubles - so you could get even longer strings.

Lets assume that you have decided that your program only deals in values ±(1e7-1) i.e. 0 to 9,999,999 and has two decimal places and a possible sign output which gives a required string buffer size of 7=1(sign)+1(decimal point)+2(precision) = 11 characters.

You will get the following output:

buf : 1234500100000.00<0
buf : 1234500100000.00<1
buf : 1234500100000.00<2
buf : 1234500100000.00<3
buf : 1234500100000.00<4
buf : 1234500100000.00<5
buf : 1234500100000.00<6
buf : 1234500100000.00<7
buf : 1234500100000.00<8
buf : 1234500100000.00<9
buf : 1234500100000.00<10
buf : 1234500100000.00<11
buf : 1234500100000.00<12
buf : 1234500100000.00<13
buf : 1234500100000.00<14
buf : 1234500100000.00<15
buf : 1234500100000.00<16
buf :  1234500100000.00<17
buf :   1234500100000.00<18
buf :    1234500100000.00<19

Here the output string is already 16 characters long from the very first conversion! the width parameter does not limit the output string length. The buffer is overwritten i.e. characters are output past the end of the length of the buffer!

Note: This is why the width parameter is specified as minimum.

Yes, in this case it is artificial as the floating point value is set within the code itself. However, if you decode a value from an input device e.g. a keyboard, a user could enter that value and cause a memory overwrite! This will cause unforeseen actions in your system. The solution is to always check the values of user input before sending the float value to dtostrf.

TIP: Always check the size of a float before sending it to dtostrf.

A simple bit of code will check the float value before use:

if (v>1e7) {return;}

You could write "OVF" (indicating overflow) to the buffer to indicate to the user that there's a problem.

Arduino Float to String: width can be negative?

If you look at the parameter specifiction, you can define a negative width. That would make no sense as you can't have less than zero spaces but it does not mean that.

A negative width is used to indicate alignment in the output string and it means keep the string number left aligned if there is more space than the output string length.

The following program changes the width parameter (from 0 to -19) while converting the floating point number 1.2345e12 to a string.

void setup() {
char buf[12];

Serial.begin(115200);

float v = 1.2345e6F;

for (int i=0;i<20;i++) {
dtostrf(v,-i,2,buf);
Serial.print("buf :");
Serial.print(buf);
Serial.print("<");
Serial.println(i);
}
}

void loop() {
}

Now the output will be

buf :1234500.00<0
buf :1234500.00<1
buf :1234500.00<2
buf :1234500.00<3
buf :1234500.00<4
buf :1234500.00<5
buf :1234500.00<6
buf :1234500.00<7
buf :1234500.00<8
buf :1234500.00<9
buf :1234500.00<10
buf :1234500.00 <11
buf :1234500.00  <12
buf :1234500.00   <13
buf :1234500.00    <14
buf :1234500.00     <15
buf :1234500.00      <16
buf :1234500.00       <17
buf :1234500.00        <18
buf :1234500.00         <19

Notice how dtostrf again outputs the string even though the width parameter is less than the string (up to width = 10).

Arduino Float to String: Conclusion

The function dtostrf is the only way to convert a float to a string in an Arduino Uno (or other 8 bit Arduinos) - 32bit processors e.g. ESP32 will implement the full sprintf so you won't need dtostrf for Arduino float to string conversion.

dtostrf is a useful function but can cause memory overwrite as explored above. Always check the input value for size before using it in dtostrf to stop buffer overwrite.

Written by John Main, who has a degree in Electronic Engineering.