Implémentation minimale de sprintf ou printf

Je travaille sur un DSP intégré dans lequel la vitesse est cruciale et la mémoire très courte.

Pour le moment, sprintf utilise le plus de ressources de toutes les fonctions de mon code. Je ne l’utilise que pour formater du texte simple: %d, %e, %f, %s , rien avec une précision ou des manipulations exotiques.

Comment puis-je implémenter une fonction de base sprintf ou printf qui conviendrait mieux à mon utilisation?

Celui-ci suppose l’existence d’un itoa pour convertir un int en représentation de caractère et d’un fputs pour écrire une chaîne où vous le souhaitez.

La sortie en virgule flottante est non conforme à au moins un égard: elle ne tente pas d’arrondir correctement, contrairement à la norme, de sorte que si vous avez (par exemple) une valeur de 1.234 qui est stockée en interne sous la valeur 1.2399999774 , être imprimé comme 1.2399 au lieu de 1.2340 . Cela économise un peu de travail et rest suffisant pour la plupart des tâches courantes.

Cela prend également en charge %c et %x en plus des conversions que vous avez demandées, mais elles sont assez simples à supprimer si vous souhaitez vous en débarrasser (et vous éviterez ainsi un peu de mémoire).

 #include  #include  #include  #include  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 *ssortingng_temp; double double_temp; char ch; int length = 0; char buffer[512]; while ( ch = *fmt++) { if ( '%' == ch ) { switch (ch = *fmt++) { /* %% - print out a single % */ case '%': fputc('%', file); length++; break; /* %c: print out a character */ case 'c': char_temp = va_arg(arg, int); fputc(char_temp, file); length++; break; /* %s: print out a ssortingng */ case 's': ssortingng_temp = va_arg(arg, char *); fputs(ssortingng_temp, file); length += strlen(ssortingng_temp); break; /* %d: print out an int */ case 'd': int_temp = va_arg(arg, int); itoa(int_temp, buffer, 10); fputs(buffer, file); length += strlen(buffer); break; /* %x: print out an 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 a fixed conversion of a double value to a string, with a precision of 5 decimal digits. * Values with absolute values less than 0.000001 are rounded to 0.0 * Note: this blindly assumes that the buffer will be large enough to hold the largest possible result. * The largest value we expect is an IEEE 754 double precision real, with maximum magnitude of approximately * e+308. The C standard requires an implementation to allow a single conversion to produce up to 512 * characters, so that's what we really expect as the 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++ = '.'; for (int i = 0; i < 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); for (int i = 0; i < sizeof(floats) / sizeof(floats[0]); i++) my_printf("%f, %e\n", floats[i], floats[i]); return 0; } #endif