Cost fprintf

I am developing a C ++ embedded application for a platform with limited code / data RAM, but rather unlimited RAM for using the file system.

When looking for code size reductions, I realized that fprintf () line exclusion makes a big contribution to the size of the generated code.

My questions: 1. Why is the cost of fprintf so high? 2. If I excluded the functionality of fprintf, what would be the alternative to generating log files that describe events when the application starts?

+2
source share
4 answers

The answer to your first question depends on the compiler you use; You can get the final answer by examining your compiler. As GrahamS noted, implementing a formatter can be complicated.

Try using fputs instead of fprintf to avoid formatting.

0
source

On embedded systems, printf can sometimes drag and drop all floating point support for format strings such as %f .

More intelligent environments will make floating-point options for printf optional.

But even for integers in printf there is a lot of general purpose code, and you may find it more compact to write your own routines that suit your specific needs, for example:

 outInt (char *buff, int intVal); outChr (char *buff, char chVal); outStr (char *buff, char *strVal); 

etc., for writing to buffers, then outBuff (char *buff) to send it to a file or standard output.


For example, if you control the data used (without line overflows, 16-bit binary additions, etc.), you can use the following functions:

 #include <stdio.h> #include <stdlib.h> #include <string.h> void outChr (char *buff, char chVal) { *buff++ = chVal; *buff = '\0'; } void outStr (char *buff, char *strVal) { strcpy (buff, strVal); } 

 void outInt (char *buff, int intVal) { int divisor = 10000, printing = 0; // Special cases. if (intVal == -32768) { outStr (buff, "-32768"); return; } if (intVal == 0) { outChr (buff, '0'); return; } // Handle negatives. if (intVal < 0) { outChr (buff++, '-'); intVal = -intVal; } // Handle non-zero positives <= 32767. while (divisor > 0) { if ((intVal >= divisor) || printing) { outChr (buff++, "0123456789"[intVal/divisor]); printing = 1; } intVal = intVal % divisor; divisor /= 10; } } 

 int main (int argc, char *argv[]) { char buff[1000]; int i; for (i = 1; i < argc; i++) { outInt (buff, atoi (argv[i])); printf ("[%s] -> [%s]\n", argv[i], buff); } return 0; } 

Launch with:

 pax$ tstprg 32767 10000 9999 10 9 1 0 -1 -9 -10 -99 -10000 -32767 -32768 

outputs:

 [32767] -> [32767] [10000] -> [10000] [9999] -> [9999] [10] -> [10] [9] -> [9] [1] -> [1] [0] -> [0] [-1] -> [-1] [-9] -> [-9] [-10] -> [-10] [-99] -> [-99] [-10000] -> [-10000] [-32767] -> [-32767] [-32768] -> [-32768] 

These functions should be relatively small in size, as they focus on specific needs, rather than the much more general printf family.

+16
source

A reasonable amount of code is required to ensure full compatibility with ANSI printf .

Some built-in environments offer several different versions of printf , which are significantly smaller because they offer only select features.

For example, the IAR C / C ++ compiler for MSP430 (PDF) offers Tiny, Small, Large, and Full printf options, with a Tiny version that supports only basic specifications ( c, d, i, o, p, s, u, X, x, and % ) without support for multibytes, floats, modifiers of length, width and accuracy.

If your environment offers this option, choose the version of printf (and scanf ) that suits your needs and knows the limitations.

If your environment does not offer this option, take a look at the various β€œtiny” alternative printf implementations (such as this one from Kustaa Nyholm SpareTimeLabs ).

+5
source

I can imagine three scenarios:

  • Each time you delete the fprintf line, the code size drops slightly, and when you delete the last final, it also drops a little.
  • When you delete the last commit, the code size drops significantly.
  • Each time you delete one instance of fprint, the code size is significantly reduced.

In scenario 1, this is not fprintf, but a criminal, but rather the string literals that you pass to it. You need to get these lines from your code, either by using very short, short messages, or by storing the lines in a file and referring to them using some form of identifier in the code (although this leads to a performance hit)

In scenario 2, fprintf is (probably) the main culprit. This is a pretty complicated function that can format all data types in various ways - so it takes quite a bit of code. When you delete the last use, the linker removes it from the final binaries, making them smaller. Instead, try using std :: ofstream. If you only insert (for example) ints and lines into the output file, then only the code for processing ints and lines is connected.

Scenario 3 is very unlikely - and will probably indicate that fprintf is embedded wherever you use it.

Hope this helps

+2
source

All Articles