简体   繁体   English

fprintf的成本

[英]cost of fprintf

I am developing an embedded application in C++ for a platform with limited code/data RAM, but rather unlimited RAM for filesystem usage. 我正在用C ++开发一个嵌入式应用程序,用于具有有限代码/数据RAM的平台,但是对于文件系统的使用而言是无限的RAM。

While looking for reducing the code size, I realized that excluding fprintf() lines contributed a lot to the size of generated code. 在寻找减少代码大小的同时,我意识到排除fprintf()行对生成代码的大小贡献很大。

My questions are : 1. Why is the cost of fprintf so high ? 我的问题是:1。为什么fprintf的成本如此之高? 2. If I exclude the fprintf functionality, what would be the alternative to generate log files describing the occurances through the application run ? 2.如果我排除了fprintf功能,那么生成描述通过应用程序运行的出现的日志文件的替代方法是什么?

In embedded systems, printf can sometimes drag in all the floating point support for format strings like %f . 在嵌入式系统中, printf有时会拖动格式字符串(如%f所有浮点支持。

More intelligent environments will make the floating point options for printf an optional thing. 更智能的环境将使printf的浮点选项成为可选项。

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: 但即使对于整数, printf也有很多通用代码,你可能会发现根据自己的特定需求编写自己的例程会更紧凑,例如:

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. 等等,用于写入缓冲区,然后用outBuff (char *buff)将其发送到文件或标准输出。


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: 例如,如果您控制正在使用的数据(没有字符串溢出,16位二进制补码整数等),您可以使用以下函数:

#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. 这些功能应该相对较小,因为它们针对特定需求而不是更普遍的printf系列。

It takes a reasonable amount of code to provide the full ANSI compliant printf functionality. 它需要合理数量的代码才能提供完全符合ANSI标准的printf功能。

Some embedded environments offer several different versions of printf that are considerably smaller, as they only offer selected functionality. 某些嵌入式环境提供了几个不同版本的printf ,它们相当小,因为它们只提供所选功能。

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. 例如, 用于MSP430IAR C / C ++编译器(PDF)提供了printf格式化程序的TinySmallLargeFull实现, Tiny版本仅支持基本说明符( c, d, i, o, p, s, u, X, x, and % ),不支持多字节,浮点数,长度修饰符,宽度和精度。

If your environment offers this choice then select the version of printf (and scanf ) that matches your needs and be aware of the limitations. 如果您的环境提供此选择,请选择符合您需求的printf (和scanf )版本,并了解其局限性。

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 ). 如果您的环境不提供此选择,请查看可用的各种“微小”替代printf实现(例如来自SpareTimeLabs的Kustaa Nyholm的这一实现 )。

I can think of three scenarios: 我可以想到三种情况:

  1. Each time you remove a fprintf line the code size drops slightly, and when you remove the very last fprint it also drops slightly. 每次删除fprintf行时,代码大小都会略微下降,当您删除最后一个fprint时,它也会略微下降。
  2. When you remove the very last fprint the code size drops significantly. 当您删除最后一个fprint时,代码大小会显着下降。
  3. Every time you remove one instance of fprint the code size drops significantly. 每次删除一个fprint实例时,代码大小都会显着下降。

In scenario 1, it isn't fprintf that is the culprit, but rather the string literals that you are passing to it. 在场景1中,不是fprintf是罪魁祸首,而是你传递给它的字符串文字。 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) 您需要从代码中获取这些字符串,方法是使用非常简短的简洁消息,或者将字符串存储在文件中并通过代码中的某种形式的ID引用它们(尽管这会导致性能下降)

In scenario 2, fprintf is (probably) the main culprit. 在方案2中,fprintf中 (可能)的罪魁祸首。 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. 尝试使用std :: ofstream代替。 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. 场景3是不太可能的 - 并且可能表明fprintf在您使用它的任何地方都被内联

Hope this helps 希望这可以帮助

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. 正如GrahamS所指出的,格式化程序的实现可能很复杂。

Try using fputs instead of fprintf to avoid the formatter. 尝试使用fputs而不是fprintf来避免格式​​化程序。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM