Guys, I want to know if float
variables can be used in sprintf()
function.
Like, if we write:
sprintf(str,"adc_read = %d \n",adc_read);
where adc_read
is an integer variable, it will store the string
"adc_read = 1023 \n"
in str
(assuming that adc_read = 1023
)
How can I use a float variable in place of integer?
This question is related to
c
embedded
floating-point
printf
Isn't something like this really easier:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char str[10];
float adc_read = 678.0123;
dtostrf( adc_read, 3, 4, temp );
sprintf(str,"adc_read = %10s \n", temp);
printf(temp);
Yes you can. However, it depends on the C-library that you are linking against and you need to be aware of the consequences.
Since you are programming for embedded applications, realise that floating-point support is emulated for a lot of embedded architectures. Compiling in this floating-point support will end up increasing the size of your executable significantly.
use the %f
modifier:
sprintf (str, "adc_read = %f\n", adc_read);
For instance:
#include <stdio.h>
int main (void)
{
float x = 2.5;
char y[200];
sprintf(y, "x = %f\n", x);
printf(y);
return 0;
}
Yields this:
x = 2.500000
%g can do this:
#include <stdio.h>
int main() {
float w = 234.567;
char x[__SIZEOF_FLOAT__];
sprintf(x, "%g", w);
puts(x);
}
Yes, and no. Despite what some other replies have said, the C compiler is required to perform conversions for sprintf()
, and all other variadic functions, as follows:
char
=> int
short
=> int
float
=> double
(and signed/unsigned variants of the above integral types)
It does this precisely because sprintf()
(and the other print()
-family functions) would be unusable without it. (Of course, they're pretty unusable as it is.)
But you cannot assume any other conversions, and your code will have undefined behaviour - read: crash! - if you do it.
Look in the documentation for sprintf for your platform. Its usually %f or %e. The only place you will find a definite answer is the documentation... if its undocumented all you can do then is contact the supplier.
What platform is it? Someone might already know where the docs are... :)
Many embedded systems have a limited snprintf function that doesn't handle floats. I wrote this, and it does the trick fairly efficiently. I chose to use 64-bit unsigned integers to be able to handle large floats, so feel free to reduce them down to 16-bit or whatever needs you may have with limited resources.
#include <stdio.h> // for uint64_t support.
int snprintf_fp( char destination[], size_t available_chars, int decimal_digits,
char tail[], float source_number )
{
int chars_used = 0; // This will be returned.
if ( available_chars > 0 )
{
// Handle a negative sign.
if ( source_number < 0 )
{
// Make it positive
source_number = 0 - source_number;
destination[ 0 ] = '-';
++chars_used;
}
// Handle rounding
uint64_t zeros = 1;
for ( int i = decimal_digits; i > 0; --i )
zeros *= 10;
uint64_t source_num = (uint64_t)( ( source_number * (float)zeros ) + 0.5f );
// Determine sliding divider max position.
uint64_t div_amount = zeros; // Give it a head start
while ( ( div_amount * 10 ) <= source_num )
div_amount *= 10;
// Process the digits
while ( div_amount > 0 )
{
uint64_t whole_number = source_num / div_amount;
if ( chars_used < (int)available_chars )
{
destination[ chars_used ] = '0' + (char)whole_number;
++chars_used;
if ( ( div_amount == zeros ) && ( zeros > 1 ) )
{
destination[ chars_used ] = '.';
++chars_used;
}
}
source_num -= ( whole_number * div_amount );
div_amount /= 10;
}
// Store the zero.
destination[ chars_used ] = 0;
// See if a tail was specified.
size_t tail_len = strlen( tail );
if ( ( tail_len > 0 ) && ( tail_len + chars_used < available_chars ) )
{
for ( size_t i = 0; i <= tail_len; ++i )
destination[ chars_used + i ] = tail[ i ];
chars_used += tail_len;
}
}
return chars_used;
}
main()
{
#define TEMP_BUFFER_SIZE 30
char temp_buffer[ TEMP_BUFFER_SIZE ];
char degrees_c[] = { (char)248, 'C', 0 };
float float_temperature = 26.845f;
int len = snprintf_fp( temp_buffer, TEMP_BUFFER_SIZE, 2, degrees_c, float_temperature );
}
Don't expect sprintf (or any other function with varargs) to automatically cast anything. The compiler doesn't try to read the format string and do the cast for you; at runtime, sprintf has no meta-information available to determine what is on the stack; it just pops bytes and interprets them as given by the format string. sprintf(myvar, "%0", 0); immediately segfaults.
So: The format strings and the other arguments must match!
Similar to paxdiablo above. This code, inserted in a wider app, works fine with STM32 NUCLEO-F446RE.
#include <stdio.h>
#include <math.h>
#include <string.h>
void IntegFract(char *pcIntegStr, char *pcFractStr, double dbValue, int iPrecis);
main()
{
char acIntegStr[9], acFractStr[9], char counter_buff[30];
double seconds_passed = 123.0567;
IntegFract(acIntegStr, acFractStr, seconds_passed, 3);
sprintf(counter_buff, "Time: %s.%s Sec", acIntegStr, acFractStr);
}
void IntegFract(char *pcIntegStr, char *pcFractStr, double dbValue, int
iPrecis)
{
int iIntegValue = dbValue;
int iFractValue = (dbValue - iIntegValue) * pow(10, iPrecis);
itoa(iIntegValue, pcIntegStr, 10);
itoa(iFractValue, pcFractStr, 10);
size_t length = strlen(pcFractStr);
char acTemp[9] = "";
while (length < iPrecis)
{
strcat(acTemp, "0");
length++;
}
strcat(acTemp, pcFractStr);
strcpy(pcFractStr, acTemp);
}
counter_buff would contain 123.056 .
Don't do this; integers in C/C++ are always rounded down so there is no need to use the floor function.
char str[100];
int d1 = value;
Better to use
int d1 = (int)(floor(value));
Then you won't get rounding up of the integer part (68.9999999999999999 becomes 69.00..). 68.09999847 instead of 68.1 is difficult to avoid - any floating point format has limited precision.
Yes of course, there is nothing special with floats. You can use the format strings as you use in printf() for floats and anyother datatypes.
EDIT I tried this sample code:
float x = 0.61;
char buf[10];
sprintf(buf, "Test=%.2f", x);
printf(buf);
Output was : Test=0.61
Yes, use %f
Source: Stackoverflow.com