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:
  • Why does my program output '?' when I use sprintf for floats?

  • How to use the dtostrf function to convert a float into a string.

  • Beware of the one big problem with dtostrf (width parameter).

  • Find out exactly how dtosrtf works here.
arduino float to string - how to do it easily with code examples
 

In C there are two types of real numbers:

   "float" and "double"

Float uses 32bits, and double usually uses 64 bits, but in 8 bit Arduino code both default to 32bits.

Why do you need to know this. Ans: It explains the naming of the function that you need to do the conversion: dtostrf - the d stands for double.



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

For an Arduino Uno both types "float" and "double" default to 32bits.

For an ESP32 or Arduino Due, you'll get 32bit and 64bit respectively (so you get higher precision floating point numbers if you use double in a 32 bit processor).

Arduino sprintf float not working

Or why does my program output "?" when I print a float?

You're not imagining it, this is why sprintf doesn’t work with float on the Arduino: Basically sprintf does not support floats!

I was recently updating a program and wanted to print out a formatted float with one decimal place; putting it into a string buffer - I wanted to put the formatted output onto an OLED display right aligned - so needed to calculate the x position i.e. the left starting point of the text to be output. That means getting the floating point value into a string before printing it.

Normally you can use an OLED ibrary function that mimics the Arduino Serial.print e.g. oledPrint(fNum,1) but that prints directly to the OLED at the next cursor position. The ',1' above gives 1 decimal place of precision.

To get the value into a char buffer, the usual program you use (in C programming) is sprintf (print to string buffer formatted) as follows:

sprintf(buf,"%.1f",fC);

I forgot that Arduino does not support float conversion within sprintf and used the code above - that is also due to the fact that you can write the code for an ESP32 - and it works! - it uses a different compiler under the hood.

This code, is valid C code, and will compile in the standard Arduino compiler. The problem is that the output will be a query '?' ! 

In Arduino code, output of floating point values using sprintf is not supported...

...so you have to work round it using the function dtostr().

The function sprintf float shows question mark

This is the Arduino compiled executable telling you that floats are not supported in sprintf!

Arduino Float to String: Conversion Function - dtostrf

The dtostrf function is an Arduino sprintf float workaround, allowing you to convert a floating point number directly into a string.

It's not as convenient as sprintf so you'll have to mess around with string manipulation code such as strncpy to create a complete string that you would otherwise easily obtain with sprintf.

float to string dtostrf

Warning: 'Min. chars in output' - width - should be the max buffer size but it's not!. It means the output may be longer than you expect. (See later examples for what this means).

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

    dtostrf - Double To String Function.

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.

Don't be fooled - you think this is the maximum string output buffer size - it's not - it is really a formatting mechanism (left or right align - See below). The number of characters output from the dtostrf function is determined only by the string size of the converted float!

If the 'float' string size is smaller, then you get space padding to left or right (+width or -width). If the string is bigger the function just outputs the whole lot!
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

Unexpected operation using the width parameter. The width parameter is not the max buffer size. It's real use is to add spaces to the left if the converted string is smaller than the value of width! See the output from the example below.

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 operation withn dtostrf, 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 examines how the width parameter is used in output string generation.

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[25];

  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 the 'string' output length 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 regardless of the length of the buffer! Make sure it is big enough and do checks on the input value before using dtostrf.

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.

The function 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 catch buffer overwrite before it happens.

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


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