C语言 如何将 printf() 包装到函数或宏中?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/20639632/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 10:31:07  来源:igfitidea点击:

How to wrap printf() into a function or macro?

cloggingc99word-wrap

提问by Vorac

This sounds a little like an interview question,but is actually a practical problem.

这听起来有点像面试问题,但实际上是一个实际问题。

I am working with an embedded platform, and have available only the equivalents of those functions:

我正在使用嵌入式平台,并且只有这些功能的等效项:

  • printf()
  • snprintf()
  • 打印输出()
  • snprintf()

Furthermore, the printf() implementation (and signature) is likely to change in the near future, so calls to it have to reside in a separate module, in order to be easy to migrate later.

此外, printf() 实现(和签名)在不久的将来可能会发生变化,因此对其的调用必须驻留在单独的模块中,以便以后易于迁移。

Given those, can I wrap logging calls in some function or macro? The goal is that my source code calls THAT_MACRO("Number of bunnies: %d", numBunnies);in a thousand places, but calls to the above functions are seen only in one place.

鉴于这些,我可以将日志调用包装在某个函数或宏中吗?目标是我的源代码THAT_MACRO("Number of bunnies: %d", numBunnies);在一千处调用,但对上述函数的调用只在一个地方看到。

Compiler: arm-gcc -std=c99

编译器:arm-gcc -std=c99

回答by Sergey L.

There are 2 ways to do this:

有两种方法可以做到这一点:

  1. Variadric macro

    #define my_printf(...) printf(__VA_ARGS__)
    
  2. function that forwards 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);
    }
    
  1. 可变宏

    #define my_printf(...) printf(__VA_ARGS__)
    
  2. 转发功能 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);
    }
    

There are also vsnprintf, vfprintfand whatever you can think of in stdio.

还有vsnprintfvfprintf无论你能想到什么stdio

回答by ldav1s

Since you can use C99, I'd wrap it in a variadic macro:

由于您可以使用 C99,我会将它包装在一个可变参数宏中

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

since you didn't say that you have vprintfor something like it. If you do have something like it, you could wrap it in a function like Sergey L has provided in his answer.

因为你没有说你有vprintf或类似的东西。如果你确实有类似的东西,你可以将它包装在像 Sergey L 在他的回答中提供的函数中。



Edit:

编辑:

The above TM_PRINTF does not work with an empty VA_ARGS list. At least in GCC it is possible to write:

上述 TM_PRINTF 不适用于空的 VA_ARGS 列表。至少在 GCC 中可以这样写:

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

The two ## signs remove remove the excess comma in front of them them if __VA_ARGS__is empty.

两个 ## 符号 remove 如果__VA_ARGS__为空,则删除它们前面多余的逗号。

回答by unwind

If you can live with having to wrap the call in twoparentheses, you can do it like this:

如果您可以忍受将调用括在两个括号中,您可以这样做:

#define THAT_MACRO(pargs)    printf pargs

Then use it:

然后使用它:

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

This works since from the preprocessor's point of view, the entire list of arguments becomes one macro argument, which is substituted with the parenthesis.

这是有效的,因为从预处理器的角度来看,整个参数列表变成了一个宏参数,用括号代替。

This is better than just plain doing

这比简单的做要好

#define THAT_MACRO printf

Since it allows you to define it out:

因为它允许您定义它:

#define THAT_MACRO(pargs)  /* nothing */

This will "eat up" the macro arguments, they will never be part of the compiled code.

这将“吃掉”宏参数,它们永远不会成为编译代码的一部分。

UPDATEOf course in C99 this technique is obsolete, just use a variadic macro and be happy.

更新当然在 C99 中这种技术已经过时了,只需使用可变参数宏就可以了。

回答by Felipe Lavratti

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

The ##token will enable the usage TM_PRINTF("aaa");

##令牌将启用使用率TM_PRINTF("aaa");

回答by EKons

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

This works like this:

这像这样工作:

It defines the parameterized macro PRINTF to accept (up to) infinite arguments, then preprocesses it from PRINTF(...)to printf(__VA_ARGS__). __VA_ARGS__is used in parameterized macro definitions to denote the arguments given ('cause you can't name infinite arguments, can you?).

它定义了参数宏PRINTF接受(高达)无限的参数,然后从预处理它PRINTF(...)printf(__VA_ARGS__)__VA_ARGS__用于参数化宏定义来表示给定的参数(因为你不能命名无限参数,你能吗?)。

回答by Alice

Limited library? Embedded system? Need as much performance as possible? No problem!

图书馆有限?嵌入式系统?需要尽可能多的性能?没问题!

As demonstrated in this answer to this question, you can use assembly language to wrap function which do not accept VA_LIST into ones that do, implementing your own vprintf at little cost!

如this answer to this question 所示,您可以使用汇编语言将不接受 VA_LIST 的函数包装到接受 VA_LIST 的函数中,以很少的成本实现您自己的 vprintf !

While this will work, and almost certainly result in the performance as well as abstraction you want, I would just recommend you get a more feature filled standard library, perhaps by slicing parts of uClibc. Such a solution is surely to be a more portable and overall more useful answer than using assembly, unless you absolutely need every cycle.

虽然这会起作用,并且几乎肯定会产生您想要的性能和抽象,但我只建议您获得一个功能更多的标准库,也许是通过切片uClibc 的一部分。除非您绝对需要每个周期,否则这样的解决方案肯定是比使用汇编更便携且整体更有用的答案。

That's why such projects exist, after all.

毕竟,这就是存在此类项目的原因。