Подтвердить что ты не робот

Как перенести printf() в функцию или макрос?

Это звучит немного как вопрос интервью, но на самом деле это практическая проблема.

Я работаю со встроенной платформой и имею в наличии только эквиваленты этих функций:

  • Е()
  • snprintf()

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

Учитывая эти возможности, могу ли я обменивать вызовы журналов в некоторых функциях или макросах? Цель состоит в том, что мой исходный код вызывает THAT_MACRO("Number of bunnies: %d", numBunnies); в тысячах мест, но вызовы к вышеуказанным функциям видны только в одном месте.

Компилятор: arm-gcc -std = c99

4b9b3361

Ответ 1

Поскольку вы можете использовать C99, я бы обернул его в переменный макрос:

#define TM_PRINTF(f_, ...) printf((f_), __VA_ARGS__)
#define TM_SNPRINTF(s_, sz_, f_, ...) snprintf((s_), (sz_), (f_), __VA_ARGS__)

так как вы не сказали, что у вас есть vprintf или что-то в этом роде. Если у вас есть что-то вроде этого, вы можете обернуть его функцией, подобной Сергею L, предоставленной в его ответе.

Ответ 2

Есть два способа сделать это:

  • Вариадический макрос

    #define my_printf(...) printf(__VA_ARGS__)
    
  • которая пересылает va_args

    #include <stdarg.h>
    #include <stdio.h>
    
    void my_printf(const char *fmt, ...) {
        va_list args;
        va_start(args, fmt);
        vprintf(fmt, args);
        va_end(args);
    }
    

Есть также vsnprintf, vfprintf и все, что вы можете представить в stdio.

Ответ 3

Если вы можете жить с необходимостью обертывания вызова в двух круглых скобках, вы можете сделать это следующим образом:

#define THAT_MACRO(pargs)    printf pargs

Затем используйте его:

THAT_MACRO(("This is a string: %s\n", "foo"));
           ^
           |
          OMG

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

Это лучше, чем просто делать

#define THAT_MACRO printf

Так как он позволяет определить его:

#define THAT_MACRO(pargs)  /* nothing */

Это "съедает" макрокоманды, они никогда не будут частью скомпилированного кода.

ОБНОВЛЕНИЕ Конечно, в C99 этот метод устарел, просто используйте переменный макрос и будьте счастливы.

Ответ 4

#define TM_PRINTF(f_, ...) printf((f_), ##__VA_ARGS__)

Ток ## позволит использовать TM_PRINTF("aaa");

Ответ 5

#define PRINTF(...) printf(__VA_ARGS__)

Это работает следующим образом:

Он определяет параметризованный макрос PRINTF для принятия (до) бесконечных аргументов, затем препроцессор от PRINTF(...) до printf(__VA_ARGS__). __VA_ARGS__ используется в параметризованных определениях макросов для обозначения приведенных аргументов (потому что вы не можете назвать бесконечные аргументы, не так ли?).

Ответ 6

Ограниченная библиотека? Встроенная система? Вам нужно как можно больше производительности? Нет проблем!

Как показано в этом ответе на этот вопрос, вы можете использовать язык ассемблера для переноса функции, которая не принимает VA_LIST в те, которые делают, реализуя свой собственный vprintf при небольших стоимость!

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

Вот почему такие проекты существуют.