c - Minimal implementation of sprintf or printf -
i'm working on embedded dsp speed crucial, , memory short.
at moment, sprintf uses resources of function in code. use format simple text: %d, %e, %f, %s, nothing precision or exotic manipulations.
how can implement basic sprintf or printf function more suitable usage?
this 1 assumes existence of itoa convert int character representation, , fputs write out string wherever want go.
the floating point output non-conforming in @ least 1 respect: makes no attempt @ rounding correctly, standard requires, if have have (for example) value of 1.234 internally stored 1.2399999774, it'll printed out 1.2399 instead of 1.2340. saves quite bit of work, , remains sufficient typical purposes.
this supports %c , %x in addition conversions asked about, they're pretty trivial remove if want rid of them (and doing save little memory).
#include <stdarg.h> #include <stdio.h> #include <string.h> #include <windows.h> static void ftoa_fixed(char *buffer, double value); static void ftoa_sci(char *buffer, double value); int my_vfprintf(file *file, char const *fmt, va_list arg) { int int_temp; char char_temp; char *string_temp; double double_temp; char ch; int length = 0; char buffer[512]; while ( ch = *fmt++) { if ( '%' == ch ) { switch (ch = *fmt++) { /* %% - print out single % */ case '%': fputc('%', file); length++; break; /* %c: print out character */ case 'c': char_temp = va_arg(arg, int); fputc(char_temp, file); length++; break; /* %s: print out string */ case 's': string_temp = va_arg(arg, char *); fputs(string_temp, file); length += strlen(string_temp); break; /* %d: print out int */ case 'd': int_temp = va_arg(arg, int); itoa(int_temp, buffer, 10); fputs(buffer, file); length += strlen(buffer); break; /* %x: print out int in hex */ case 'x': int_temp = va_arg(arg, int); itoa(int_temp, buffer, 16); fputs(buffer, file); length += strlen(buffer); break; case 'f': double_temp = va_arg(arg, double); ftoa_fixed(buffer, double_temp); fputs(buffer, file); length += strlen(buffer); break; case 'e': double_temp = va_arg(arg, double); ftoa_sci(buffer, double_temp); fputs(buffer, file); length += strlen(buffer); break; } } else { putc(ch, file); length++; } } return length; } int normalize(double *val) { int exponent = 0; double value = *val; while (value >= 1.0) { value /= 10.0; ++exponent; } while (value < 0.1) { value *= 10.0; --exponent; } *val = value; return exponent; } static void ftoa_fixed(char *buffer, double value) { /* carry out fixed conversion of double value string, precision of 5 decimal digits. * values absolute values less 0.000001 rounded 0.0 * note: blindly assumes buffer large enough hold largest possible result. * largest value expect ieee 754 double precision real, maximum magnitude of approximately * e+308. c standard requires implementation allow single conversion produce 512 * characters, that's expect buffer size. */ int exponent = 0; int places = 0; static const int width = 4; if (value == 0.0) { buffer[0] = '0'; buffer[1] = '\0'; return; } if (value < 0.0) { *buffer++ = '-'; value = -value; } exponent = normalize(&value); while (exponent > 0) { int digit = value * 10; *buffer++ = digit + '0'; value = value * 10 - digit; ++places; --exponent; } if (places == 0) *buffer++ = '0'; *buffer++ = '.'; while (exponent < 0 && places < width) { *buffer++ = '0'; --exponent; ++places; } while (places < width) { int digit = value * 10.0; *buffer++ = digit + '0'; value = value * 10.0 - digit; ++places; } *buffer = '\0'; } void ftoa_sci(char *buffer, double value) { int exponent = 0; int places = 0; static const int width = 4; if (value == 0.0) { buffer[0] = '0'; buffer[1] = '\0'; return; } if (value < 0.0) { *buffer++ = '-'; value = -value; } exponent = normalize(&value); int digit = value * 10.0; *buffer++ = digit + '0'; value = value * 10.0 - digit; --exponent; *buffer++ = '.'; (int = 0; < width; i++) { int digit = value * 10.0; *buffer++ = digit + '0'; value = value * 10.0 - digit; } *buffer++ = 'e'; itoa(exponent, buffer, 10); } int my_printf(char const *fmt, ...) { va_list arg; int length; va_start(arg, fmt); length = my_vfprintf(stdout, fmt, arg); va_end(arg); return length; } int my_fprintf(file *file, char const *fmt, ...) { va_list arg; int length; va_start(arg, fmt); length = my_vfprintf(file, fmt, arg); va_end(arg); return length; } #ifdef test int main() { float floats[] = { 0.0, 1.234e-10, 1.234e+10, -1.234e-10, -1.234e-10 }; my_printf("%s, %d, %x\n", "some string", 1, 0x1234); (int = 0; < sizeof(floats) / sizeof(floats[0]); i++) my_printf("%f, %e\n", floats[i], floats[i]); return 0; } #endif
Comments
Post a Comment