I am developing an embedded application in C++ for a platform with limited code/data RAM, but rather unlimited RAM for filesystem usage.
While looking for reducing t
In embedded systems, printf
can sometimes drag in all the floating point support for format strings like %f
.
More intelligent environments will make the floating point options for printf
an optional thing.
But even for integers, there's a lot of general purpose code in printf
and you may find it's more compact to write your own routines, tailored to your specific needs, like:
outInt (char *buff, int intVal);
outChr (char *buff, char chVal);
outStr (char *buff, char *strVal);
and so on, for writing to buffers, then outBuff (char *buff)
for sending it to a file or standard output.
For example, if you control the data being used (no string overflow, 16-bit twos complement integers and such), 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;
}
Running this 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 since they're targeted to specific needs rather than the far more general printf
family.
I can think of three scenarios:
In scenario 1, it isn't fprintf that is the culprit, but rather the string literals that you are passing to it. You need to get these strings out of your code, either by using very short, terse messages, or by storing the strings in a file and referencing them by some form of ID within the code (although this incurs performance hits)
In scenario 2, fprintf is (probably) the main culprit. It is quite a complex function that is capable of formatting all kinds of data types in all kinds of ways - so it takes quite a bit of code space. When you remove the last use of it the linker will eliminate it from the final binaries, making them smaller. Try using std::ofstream instead. If you only ever insert (for example) ints and strings to your output file, then only the code for handling ints and strings is linked in.
Scenario 3 is very unlikely - and would probably indicate that fprintf is being inlined wherever you use it.
Hope this helps
It takes a reasonable amount of code to provide the full ANSI compliant printf
functionality.
Some embedded environments offer several different versions of printf
that are considerably smaller, as they only offer selected functionality.
For example, the IAR C/C++ Compiler for MSP430 (PDF), offers Tiny, Small, Large and Full implementations of the printf formatter, with the Tiny version only supporting the basic specifiers (c, d, i, o, p, s, u, X, x, and %
) with no support for multibytes, floats, length modifiers, width and precision.
If your environment offers this choice then select the version of printf
(and scanf
) that matches your needs and be aware of the limitations.
If your environment does not offer this choice then take a look at the various "tiny" alternative printf
implementations available (such as this one from Kustaa Nyholm of SpareTimeLabs).
The answer to your first question depends on the compiler that you are using; you can only get a definitive answer by examining your compiler. As GrahamS pointed out, formatter implementation can be complicated.
Try using fputs
instead of fprintf
to avoid the formatter.