Как перенести printf() в функцию или макрос?
Это звучит немного как вопрос интервью, но на самом деле это практическая проблема.
Я работаю со встроенной платформой и имею в наличии только эквиваленты этих функций:
Кроме того, реализация (и подпись) printf(), скорее всего, изменится в ближайшем будущем, поэтому вызовы к ней должны находиться в отдельном модуле, чтобы их можно было переносить позже.
Учитывая эти возможности, могу ли я обменивать вызовы журналов в некоторых функциях или макросах? Цель состоит в том, что мой исходный код вызывает THAT_MACRO("Number of bunnies: %d", numBunnies);
в тысячах мест, но вызовы к вышеуказанным функциям видны только в одном месте.
Компилятор: arm-gcc -std = c99
Ответы
Ответ 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. Такое решение, несомненно, будет более переносимым и общим более полезным ответом, чем использование сборки, если только вам не понадобится каждый цикл.
Вот почему такие проекты существуют.