Как объединить строки и int в C без использования sprintf? - PullRequest
2 голосов
/ 18 марта 2020

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

sprintf(txbuf, "info=>t:%d-%d-%d$%d:%d:%d", ui8Day,ui8Month, ui8Year, ui8Hour, ui8Minute, ui8Second);

PS: $, - и : просто для разделения данных.

Однако sprintf занимает много места в памяти, и я пытаюсь уменьшить размер кода. Я также попытался использовать функции strcat и strcpy, но они также увеличили размер кода.

Ответы [ 2 ]

0 голосов
/ 18 марта 2020

Вот минималистская реализация sprintf, которую вы можете использовать в качестве замены, которая поддерживает только %d, %u, %x, %s, %c и %%. Вы можете легко изменить его, удалив неиспользуемые спецификаторы преобразования:

#include <limits.h>
#include <stdarg.h>
#include <stdio.h>

int small_sprintf(char *dest, const char *fmt, ...) {
    char buf[20];
    va_list arg;
    char *p, *s;
    int n;
    unsigned int u;

    va_start(arg, fmt);

    for (p = dest; (*p++ = *fmt++) != '\0';) {
        if (fmt[-1] == '%' && *fmt != '\0') {
            p--;
            s = buf + sizeof(buf);
            *--s = '\0';
            switch (*fmt++) {
            case 'u':
                u = va_arg(arg, unsigned);
                goto conv10;
            case 'd':
                u = n = va_arg(arg, int);
                if (n < 0) {
                    *p++ = '-';
                    u = -u;
                }
            conv10:
                do { *--s = '0' + (u % 10); } while ((u /= 10) != 0);
                break;
            case 'x':
                u = va_arg(arg, unsigned);
                do { *--s = "0123456789abcdef"[u & 15]; } while ((u >>= 4) != 0);
                break;
            case 's':
                s = va_arg(arg, char *);
                break;
            case 'c':
                *--s = (char)va_arg(arg, int);
                break;
            default:
                *--s = fmt[-1];
                break;
            }
            while ((*p = *s++) != '\0')
                p++;
        }
    }
    va_end(arg);
    return p - 1 - dest;
}

int main() {
    char buf[128];
    int n = small_sprintf(buf, "Hello %s%c %d %d%% INT_MIN=%d, INT_MAX=%x", "world", '!', 0, 100, INT_MIN, INT_MAX);
    puts(buf);
    while (n-- > 0)
        putchar('-');
    putchar('\n');
    return 0;
}

Обратите внимание, однако, что в вашем примере, вероятно, следует использовать %02d или %.2d для получения 01 вместо 1 для минут и секунд. Для этого вы можете добавить еще один спецификатор преобразования %D с этим кодом:

        case 'D': // convert an unsigned integer as 2 decimal digits
            d = va_arg(arg, unsigned);
            *--s = '0' + u % 10;
            *--s = '0' + u / 10 % 10;
            break;
0 голосов
/ 18 марта 2020

вы можете использовать snprintf () вместо sprintf (), потому что snprintf () останавливает переполнение памяти.

...