стоимость фпринтф - PullRequest
       13

стоимость фпринтф

2 голосов
/ 02 марта 2011

Я занимаюсь разработкой встроенного приложения на C ++ для платформы с ограниченным объемом ОЗУ для кода / данных, но довольно неограниченным ОЗУ для использования файловой системы.

При поиске уменьшения размера кода я понял, что исключая fprintf ()Строки внесли большой вклад в размер сгенерированного кода.

Мои вопросы: 1. Почему стоимость fprintf так высока?2. Если я исключу функциональность fprintf, какой будет альтернатива для создания файлов журналов, описывающих вхождения во время запуска приложения?

Ответы [ 4 ]

16 голосов
/ 02 марта 2011

Во встроенных системах printf может иногда перетаскивать всю поддержку чисел с плавающей запятой для строк формата, таких как %f.

Более интеллектуальные среды сделают опции с плавающей запятой для printf опциональной вещью.

Но даже для целых чисел в printf есть много кода общего назначения, и вы можете обнаружить, что он более компактен для написания ваших собственных подпрограмм, адаптированных к вашим специфическим потребностям, таким как:

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.

5 голосов
/ 02 марта 2011

Требуется разумное количество кода, чтобы обеспечить полную совместимость с ANSI printf.

Некоторые встроенные среды предлагают несколько различных версий printf, которые значительно меньше, поскольку они предлагают только выбранные функции.

Например, IAR C / C ++ Compiler для MSP430 (PDF) , предлагает Tiny , Small , Large и Full реализации средства форматирования printf с Tiny* Версия 1018 *, поддерживающая только основные спецификаторы (c, d, i, o, p, s, u, X, x, and %) без поддержки многобайтовых операций, чисел с плавающей запятой, модификаторов длины, ширины и точности.

Если ваша среда предлагает такой выбор, выберите версию printfscanf), который соответствует вашим потребностям и учитывает ограничения.

Если ваша среда не предлагает такой выбор, взгляните на различные «крошечные» альтернативные printfдоступные реализации (такие как это от Kustaa Nyholm из SpareTimeLabs ).

2 голосов
/ 02 марта 2011

Я могу вспомнить три сценария:

  1. Каждый раз, когда вы удаляете строку fprintf, размер кода слегка уменьшается, а при удалении самого последнего отпечатка он также немного уменьшается.
  2. При удалении самого последнего отпечатка размер кода значительно уменьшается.
  3. Каждый раз, когда вы удаляете один экземпляр fprint, размер кода значительно уменьшается.

В сценарии 1 виновником является не fprintf, а строковые литералы, которые вы ему передаете. Вы должны извлечь эти строки из своего кода, используя очень короткие, краткие сообщения или сохраняя строки в файле и ссылаясь на них с помощью некоторой формы идентификатора в коде (хотя это приводит к снижению производительности)

В сценарии 2 fprintf является (вероятно) основным виновником. Это довольно сложная функция, которая способна форматировать все типы данных различными способами, поэтому она занимает довольно много места в коде. Когда вы удалите его в последний раз, компоновщик удалит его из окончательных двоичных файлов, сделав их меньше. Попробуйте вместо этого использовать std :: ofstream. Если вы когда-либо вставляете (например) целые и строковые значения в ваш выходной файл, то в этом случае связывается только код для обработки целочисленных и строковых значений.

Сценарий 3 очень маловероятен - и, вероятно, будет указывать, что fprintf встроен везде, где вы его используете.

Надеюсь, это поможет

0 голосов
/ 02 марта 2011

Ответ на ваш первый вопрос зависит от используемого вами компилятора; Вы можете получить окончательный ответ, только изучив ваш компилятор. Как указал GrahamS, реализация средства форматирования может быть сложной.

Попробуйте использовать fputs вместо fprintf, чтобы избежать форматирования.

...