fprintf的成本

时间:2011-03-02 09:39:41

标签: c++ c embedded printf

我正在用C ++开发一个嵌入式应用程序,用于具有有限代码/数据RAM的平台,而不是用于文件系统使用的无限RAM。

在寻找减少代码大小的同时,我意识到排除fprintf()行对生成代码的大小有很大贡献。

我的问题是: 1.为什么fprintf的成本如此之高? 2.如果我排除了fprintf功能,那么生成描述通过应用程序运行的出现的日志文件的替代方法是什么?

4 个答案:

答案 0 :(得分:16)

在嵌入式系统中,printf有时会拖动对%f等格式字符串的所有浮点支持。

更智能的环境将使printf的浮点选项成为可选项。

但即使是整数,printf中也有很多通用代码,您可能会发现编写自己的例程更加紧凑,根据您的特定需求量身定制,例如: / p>

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

等等,用于写入缓冲区,然后outBuff (char *buff)将其发送到文件或标准输出。


例如,如果您控制正在使用的数据(没有字符串溢出,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;
}

用以下方式运行:

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

输出:

[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]

这些功能的规模相对较小,因为它们针对的是特定需求,而不是更为一般的printf系列。

答案 1 :(得分:5)

需要合理数量的代码才能提供完全符合ANSI标准的printf功能。

某些嵌入式环境提供了几个不同版本的printf,它们相当小,因为它们只提供所选功能。

例如,IAR C/C++ Compiler for MSP430 (PDF),提供 Tiny Small Large Full 实现printf格式化程序, Tiny 版本仅支持基本说明符(c, d, i, o, p, s, u, X, x, and %),不支持多字节,浮点数,长度修饰符,宽度和精度。

如果您的环境提供此选项,请选择符合您需求的printf(和scanf)版本,并了解其中的限制。

如果您的环境不提供此选择,请查看可用的各种“微小”替代printf实施(例如this one from Kustaa Nyholm of SpareTimeLabs)。

答案 2 :(得分:2)

我可以想到三种情况:

  1. 每次删除fprintf行时,代码大小会略微下降,当您删除最后一个fprint时,它也会略微下降。
  2. 删除最后一个fprint时,代码大小会显着下降。
  3. 每次删除一个fprint实例时,代码大小都会显着下降。
  4. 在场景1中,不是fprintf是罪魁祸首,而是你传递给它的字符串文字。您需要从代码中获取这些字符串,方法是使用非常简短的简短消息,或者将字符串存储在文件中并通过代码中的某种形式的ID引用它们(尽管这会导致性能下降)

    在方案2中,fprintf (可能)是罪魁祸首。它是一个非常复杂的函数,能够以各种方式格式化各种数据类型 - 因此需要相当多的代码空间。当你删除它的最后一次使用时,链接器会将它从最终的二进制文件中删除,使它们变小。尝试使用std :: ofstream代替。如果您只在输出文件中插入(例如)整数和字符串,则只链接用于处理整数和字符串的代码。

    场景3非常不可能 - 并且可能表明fprintf在任何地方内联

    希望这有帮助

答案 3 :(得分:0)

第一个问题的答案取决于您使用的编译器;你只能通过检查你的编译器得到一个明确的答案。正如GrahamS所指出的,格式化程序的实现可能很复杂。

尝试使用fputs代替fprintf来避免使用格式化程序。