C++ 你如何创建一个只接受变量参数列表的调试函数?像 printf()

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/15240/
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-08-27 12:15:03  来源:igfitidea点击:

How do you create a debug only function that takes a variable argument list? Like printf()

c++cc-preprocessor

提问by hyperlogic

I'd like to make a debug logging function with the same parameters as printf. But one that can be removed by the pre-processor during optimized builds.

我想使用与printf. 但是在优化构建期间可以由预处理器删除的一个。

For example:

例如:

Debug_Print("Warning: value %d > 3!\n", value);

I've looked at variadic macros but those aren't available on all platforms. gccsupports them, msvcdoes not.

我看过可变参数宏,但并非在所有平台上都可用。gcc支持他们,msvc不支持。

采纳答案by hyperlogic

I still do it the old way, by defining a macro (XTRACE, below) which correlates to either a no-op or a function call with a variable argument list. Internally, call vsnprintf so you can keep the printf syntax:

我仍然用旧的方式来做,通过定义一个宏(XTRACE,下面),它与无操作或带有可变参数列表的函数调用相关联。在内部,调用 vsnprintf 以便您可以保留 printf 语法:

#include <stdio.h>

void XTrace0(LPCTSTR lpszText)
{
   ::OutputDebugString(lpszText);
}

void XTrace(LPCTSTR lpszFormat, ...)
{
    va_list args;
    va_start(args, lpszFormat);
    int nBuf;
    TCHAR szBuffer[512]; // get rid of this hard-coded buffer
    nBuf = _vsnprintf(szBuffer, 511, lpszFormat, args);
    ::OutputDebugString(szBuffer);
    va_end(args);
}

Then a typical #ifdef switch:

然后是一个典型的 #ifdef 开关:

#ifdef _DEBUG
#define XTRACE XTrace
#else
#define XTRACE
#endif

Well that can be cleaned up quite a bit but it's the basic idea.

好吧,这可以清理很多,但这是基本思想。

回答by snstrand

This is how I do debug print outs in C++. Define 'dout' (debug out) like this:

这就是我在 C++ 中调试打印输出的方式。像这样定义“dout”(调试):

#ifdef DEBUG
#define dout cout
#else
#define dout 0 && cout
#endif

In the code I use 'dout' just like 'cout'.

在代码中,我使用 'dout' 就像 'cout' 一样。

dout << "in foobar with x= " << x << " and y= " << y << '\n';

If the preprocessor replaces 'dout' with '0 && cout' note that << has higher precedence than && and short-circuit evaluation of && makes the whole line evaluate to 0. Since the 0 is not used the compiler generates no code at all for that line.

如果预处理器将 'dout' 替换为 '0 && cout' 请注意 << 的优先级高于 && 并且 && 的短路评估使整行评估为 0。 由于未使用 0,编译器根本不生成任何代码对于那条线。

回答by Graeme Perrow

Here's something that I do in C/C++. First off, you write a function that uses the varargs stuff (see the link in Stu's posting). Then do something like this:

这是我在 C/C++ 中所做的事情。首先,您编写了一个使用可变参数的函数(请参阅 Stu 帖子中的链接)。然后做这样的事情:


 int debug_printf( const char *fmt, ... );
 #if defined( DEBUG )
  #define DEBUG_PRINTF(x) debug_printf x
 #else
   #define DEBUG_PRINTF(x)
 #endif

 DEBUG_PRINTF(( "Format string that takes %s %s\n", "any number", "of args" ));

All you have to remember is to use double-parens when calling the debug function, and the whole line will get removed in non-DEBUG code.

你只需要记住在调用调试函数时使用双括号,整行将在非调试代码中被删除。

回答by Mat Noguchi

Another fun way to stub out variadic functions is:

另一种去除可变参数函数的有趣方法是:

#define function sizeof

回答by Ferruccio

@CodingTheWheel:

@CodingTheWheel:

There is one slight problem with your approach. Consider a call such as

你的方法有一个小问题。考虑一个电话,例如

XTRACE("x=%d", x);

This works fine in the debug build, but in the release build it will expand to:

这在调试版本中工作正常,但在发布版本中它将扩展为:

("x=%d", x);

Which is perfectly legitimate C and will compile and usually run without side-effects but generates unnecessary code. The approach I usually use to eliminate that problem is:

这是完全合法的 C 语言,可以编译并且通常在没有副作用的情况下运行,但会生成不必要的代码。我通常用来消除该问题的方法是:

  1. Make the XTrace function return an int (just return 0, the return value doesn't matter)

  2. Change the #define in the #else clause to:

    0 && XTrace
    
  1. 使XTrace函数返回一个int(只返回0,返回值无所谓)

  2. 将#else 子句中的#define 更改为:

    0 && XTrace
    

Now the release version will expand to:

现在发布版本将扩展为:

0 && XTrace("x=%d", x);

and any decent optimizer will throw away the whole thing since short-circuit evaluation would have prevented anything after the && from ever being executed.

任何体面的优化器都会丢弃整个事情,因为短路评估会阻止 && 之后的任何事情被执行。

Of course, just as I wrote that last sentence, I realized that perhaps the original form might be optimized away too and in the case of side effects, such as function calls passed as parameters to XTrace, it might be a better solution since it will make sure that debug and release versions will behave the same.

当然,就在我写最后一句话的时候,我意识到也许原来的形式也可能被优化掉了,在副作用的情况下,比如作为参数传递给 XTrace 的函数调用,它可能是一个更好的解决方案,因为它会确保调试和发布版本的行为相同。

回答by hyperlogic

Ah, vsprintf() was the thing I was missing. I can use this to pass the variable argument list directly to printf():

啊,vsprintf() 是我缺少的东西。我可以使用它来将变量参数列表直接传递给 printf():

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

void DBG_PrintImpl(char * format, ...)
{
    char buffer[256];
    va_list args;
    va_start(args, format);
    vsprintf(buffer, format, args);
    printf("%s", buffer);
    va_end(args);
}

Then wrap the whole thing in a macro.

然后将整个内容包装在一个宏中。

回答by Skizz

In C++ you can use the streaming operator to simplify things:

在 C++ 中,您可以使用流操作符来简化事情:

#if defined _DEBUG

class Trace
{
public:
   static Trace &GetTrace () { static Trace trace; return trace; }
   Trace &operator << (int value) { /* output int */ return *this; }
   Trace &operator << (short value) { /* output short */ return *this; }
   Trace &operator << (Trace &(*function)(Trace &trace)) { return function (*this); }
   static Trace &Endl (Trace &trace) { /* write newline and flush output */ return trace; }
   // and so on
};

#define TRACE(message) Trace::GetTrace () << message << Trace::Endl

#else
#define TRACE(message)
#endif

and use it like:

并使用它:

void Function (int param1, short param2)
{
   TRACE ("param1 = " << param1 << ", param2 = " << param2);
}

You can then implement customised trace output for classes in much the same way you would do it for outputting to std::cout.

然后,您可以按照与输出到std::cout.

回答by David Bryson

Part of the problem with this kind of functionality is that often it requires variadic macros. These were standardized fairly recently(C99), and lots of old C compilers do not support the standard, or have their own special work around.

这种功能的部分问题在于它通常需要可变参数宏。这些是最近标准化的(C99),许多旧的 C 编译器不支持该标准,或者有自己的特殊工作。

Below is a debug header I wrote that has several cool features:

下面是我写的一个调试头文件,它有几个很酷的特性:

  • Supports C99 and C89 syntax for debug macros
  • Enable/Disable output based on function argument
  • Output to file descriptor(file io)
  • 支持调试宏的 C99 和 C89 语法
  • 根据函数参数启用/禁用输出
  • 输出到文件描述符(file io)

Note: For some reason I had some slight code formatting problems.

注意:出于某种原因,我遇到了一些轻微的代码格式问题。

#ifndef _DEBUG_H_
#define _DEBUG_H_
#if HAVE_CONFIG_H
#include "config.h"
#endif

#include "stdarg.h"
#include "stdio.h"

#define ENABLE 1
#define DISABLE 0

extern FILE* debug_fd;

int debug_file_init(char *file);
int debug_file_close(void);

#if HAVE_C99
#define PRINT(x, format, ...) \
if ( x ) { \
if ( debug_fd != NULL ) { \
fprintf(debug_fd, format, ##__VA_ARGS__); \
} \
else { \
fprintf(stdout, format, ##__VA_ARGS__); \
} \
}
#else
void PRINT(int enable, char *fmt, ...);
#endif

#if _DEBUG
#if HAVE_C99
#define DEBUG(x, format, ...) \
if ( x ) { \
if ( debug_fd != NULL ) { \
fprintf(debug_fd, "%s : %d " format, __FILE__, __LINE__, ##__VA_ARGS__); \
} \
else { \
fprintf(stderr, "%s : %d " format, __FILE__, __LINE__, ##__VA_ARGS__); \
} \
}

#define DEBUGPRINT(x, format, ...) \
if ( x ) { \
if ( debug_fd != NULL ) { \
fprintf(debug_fd, format, ##__VA_ARGS__); \
} \
else { \
fprintf(stderr, format, ##__VA_ARGS__); \
} \
}
#else /* HAVE_C99 */

void DEBUG(int enable, char *fmt, ...);
void DEBUGPRINT(int enable, char *fmt, ...);

#endif /* HAVE_C99 */
#else /* _DEBUG */
#define DEBUG(x, format, ...)
#define DEBUGPRINT(x, format, ...)
#endif /* _DEBUG */

#endif /* _DEBUG_H_ */

回答by Stu

What platforms are they not available on? stdarg is part of the standard library:

它们在哪些平台上不可用?stdarg 是标准库的一部分:

http://www.opengroup.org/onlinepubs/009695399/basedefs/stdarg.h.html

http://www.opengroup.org/onlinepubs/009695399/basedefs/stdarg.h.html

Any platform not providing it is not a standard C implementation (or very, very old). For those, you will have to use varargs:

任何不提供它的平台都不是标准的 C 实现(或非常非常古老)。对于那些,你将不得不使用可变参数:

http://opengroup.org/onlinepubs/007908775/xsh/varargs.h.html

http://opengroup.org/onlinepubs/007908775/xsh/varargs.h.html

回答by Stu

Have a look at this thread:

看看这个线程:

It should answer your question.

它应该回答你的问题。