Arduino sprintf float not formatting

C++ArduinoPrintf

C++ Problem Overview


I have this arduino sketch,

char temperature[10];
float temp = 10.55;
sprintf(temperature,"%f F", temp);
Serial.println(temperature);

temperature prints out as

? F

Any thoughts on how to format this float? I need it to be a char string.

C++ Solutions


Solution 1 - C++

Due to some performance reasons %f is not included in the Arduino's implementation of sprintf(). A better option would be to use dtostrf() - you convert the floating point value to a C-style string, Method signature looks like:

char *dtostrf(double val, signed char width, unsigned char prec, char *s)

Use this method to convert it to a C-Style string and then use sprintf, eg:

char str_temp[6];

/* 4 is mininum width, 2 is precision; float value is copied onto str_temp*/
dtostrf(temp, 4, 2, str_temp);
sprintf(temperature,"%s F", str_temp);

You can change the minimum width and precision to match the float you are converting.

Solution 2 - C++

As has been stated before Float support is not included in sprintf on Arduino.

String class

Arduino has its own String class.

String value = String(3.14);

then,

char *result = value.c_str();

Constructs an instance of the String class. There are multiple versions that construct Strings from different data types (i.e. format them as sequences of characters), including:

  • a constant string of characters, in double quotes (i.e. a char array)
  • a single constant character, in single quotes
  • another instance of the String object
  • a constant integer or long integer
  • a constant integer or long integer, using a specified base
  • an integer or long integer variable
  • an integer or long integer variable, using a specified base
  • a float or double, using a specified decimal places

Solution 3 - C++

I've struggled for a few hours on getting this right, but I did finally. And this uses modern Espressif C++ provided by Platformio, and my target MCU is an ESP32.

I wanted to display a prefix label, the float/int value, then the unit, all inline.

I can't relay on seperate Serial.print() statements, as I am using an OLED display.

Here's my code example:

  int strLenLight = sizeof("Light ADC: 0000");
  int strLenTemp = sizeof("Temp: 000.0 °C");
  int strLenHumd = sizeof("Humd: 00.0 %");

  char displayLight[strLenLight] = "Light ADC: ";
  char displayTemp[strLenTemp] = "Temp: ";
  char displayHumd[strLenHumd] = "Humd: ";

  snprintf(strchr(displayLight, '\0'), sizeof(displayLight), "%d", light_value);
  snprintf(strchr(displayTemp, '\0'), sizeof(displayTemp), "%.1f °C", temperature); 
  snprintf(strchr(displayHumd, '\0'), sizeof(displayHumd), "%.1f %%", humidity); 

  Serial.println(displayLight);
  Serial.println(displayTemp);
  Serial.println(displayHumd);

Which displays:

Light ADC: 1777
Temp: 25.4 °C
Humd: 55.0 %

Solution 4 - C++

dtostrf() is deprecated, and it doesn't exist on every board core platforms. On the other hand, sprintf() doesn't format floats on AVR platforms!

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionMistergreenView Question on Stackoverflow
Solution 1 - C++Dinal24View Answer on Stackoverflow
Solution 2 - C++Cameron Lowell PalmerView Answer on Stackoverflow
Solution 3 - C++ExcaliburView Answer on Stackoverflow
Solution 4 - C++Helmut WunderView Answer on Stackoverflow