如何创建带有可变参数列表的仅调试函数? 就像 printf()
我想使用与 printf 相同的参数创建一个调试日志记录函数。 但在优化构建期间可以被预处理器删除。
例如:
Debug_Print("Warning: value %d > 3!\n", value);
我研究过可变参数宏,但它们并非在所有平台上都可用。 gcc
支持它们,msvc
不支持。
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.
For example:
Debug_Print("Warning: value %d > 3!\n", value);
I've looked at variadic macros but those aren't available on all platforms. gcc
supports them, msvc
does not.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(14)
消除可变参数函数的另一种有趣方法是:
Another fun way to stub out variadic functions is:
@CodingTheWheel:
您的方法有一个小问题。 考虑这样的调用:
This 在调试版本中工作正常,但在发布版本中它将扩展为:
这是完全合法的 C,并且将编译并通常运行而不会产生副作用,但会生成不必要的代码。 我通常用来消除这个问题的方法是:
让 XTrace 函数返回一个 int (只返回 0,返回值无关紧要)
将#else子句中的#define更改为:
<前><代码>0 && XTrace
现在发布版本将扩展为:
并且任何像样的优化器都会丢弃整个事情,因为短路评估会阻止 & 之后的任何事情。 & 从被处决开始。
当然,正如我写下最后一句话一样,我意识到也许原始形式也可能被优化掉,并且在出现副作用的情况下,例如作为参数传递给 XTrace 的函数调用,它可能是一个更好的解决方案,因为它会确保调试版本和发布版本的行为相同。
@CodingTheWheel:
There is one slight problem with your approach. Consider a call such as
This works fine in the debug build, but in the release build it will expand to:
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:
Make the XTrace function return an int (just return 0, the return value doesn't matter)
Change the #define in the #else clause to:
Now the release version will expand to:
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.
在 C++ 中,您可以使用流运算符来简化事情:
并像这样使用它:
然后,您可以为类实现自定义跟踪输出,其方式与输出到
std::cout
的方式大致相同。In C++ you can use the streaming operator to simplify things:
and use it like:
You can then implement customised trace output for classes in much the same way you would do it for outputting to
std::cout
.它们在哪些平台上不可用? stdarg 是标准库的一部分:
http://www.opengroup。 org/onlinepubs/009695399/basedefs/stdarg.h.html
任何不提供它的平台都不是标准的 C 实现(或者非常非常旧)。 对于这些,您必须使用可变参数:
http://opengroup.org/ onlinepubs/007908775/xsh/varargs.h.html
What platforms are they not available on? stdarg is part of the standard library:
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:
http://opengroup.org/onlinepubs/007908775/xsh/varargs.h.html
这种功能的部分问题在于它通常需要
可变参数宏。 这些是最近标准化的(C99),并且很多
旧的 C 编译器不支持该标准,或者有自己的特殊工作
大约。
下面是我编写的一个调试头,它有几个很酷的功能:
注意:由于某种原因,我遇到了一些轻微的代码格式问题。
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.
Below is a debug header I wrote that has several cool features:
Note: For some reason I had some slight code formatting problems.
看看这个帖子:
它应该回答您的问题。
Have a look at this thread:
It should answer your question.
这就是我使用的:
当 _DEBUG_LOG 标志关闭时,它在运行时绝对不需要任何成本。
This is what I use:
which costs absolutely nothing at run-time when the _DEBUG_LOG flag is turned off.
这是用户答案的 TCHAR 版本,因此它将作为 ASCII(正常)或 Unicode 模式(或多或少)工作。
我说“或多或少”,因为它不会自动将 ASCII 字符串参数转换为 WCHAR,但它应该可以让您摆脱大多数 Unicode 刮擦,而不必担心将格式字符串包装在 TEXT() 或前面它与 L。
很大程度上源自 MSDN:检索最后一个错误代码
This is a TCHAR version of user's answer, so it will work as ASCII (normal), or Unicode mode (more or less).
I say, "more or less", because it won't automatically convert ASCII string arguments to WCHAR, but it should get you out of most Unicode scrapes without having to worry about wrapping the format string in TEXT() or preceding it with L.
Largely derived from MSDN: Retrieving the Last-Error Code
不完全是问题中所问的内容。 但是这段代码对于调试目的很有帮助,它将打印每个变量的值及其名称。 这完全与类型无关,并且支持可变数量的参数。
甚至可以很好地显示 STL 的值,前提是您为它们重载了输出运算符
示例用途:
输出:
Not exactly what's asked in the question . But this code will be helpful for debugging purposes , it will print each variable's value along with it's name . This is completely type independent and supports variable number of arguments.
And can even display values of STL's nicely , given that you overload output operator for them
Sample Use :
Output :
今天遇到这个问题,我的解决方案是以下宏:
然后您可以像这样调用该函数:
Having come across the problem today, my solution is the following macro:
You can then call the function like this:
我仍然采用旧方法,定义一个宏(XTRACE,如下),该宏与无操作或带有变量参数列表的函数调用相关。 在内部,调用 vsnprintf 这样你就可以保留 printf 语法:
然后是一个典型的 #ifdef 开关:
嗯,这可以清理很多,但这是基本思想。
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:
Then a typical #ifdef switch:
Well that can be cleaned up quite a bit but it's the basic idea.
这就是我在 C++ 中调试打印输出的方法。 像这样定义“dout”(调试输出):
在代码中,我使用“dout”,就像“cout”一样。
如果预处理器将 'dout' 替换为 '0 && cout' 请注意 << 优先级高于 && 和&&的短路评估 使整行的计算结果为 0。由于未使用 0,编译器根本不会为该行生成任何代码。
This is how I do debug print outs in C++. Define 'dout' (debug out) like this:
In the code I use 'dout' just like 'cout'.
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.
这是我用 C/C++ 做的事情。 首先,您编写一个使用可变参数的函数(请参阅 Stu 的帖子中的链接)。 然后做这样的事情:
您所需要记住的是在调用调试函数时使用双括号,并且整行将在非调试代码中被删除。
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:
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.
啊,vsprintf() 是我缺少的东西。 我可以使用它将变量参数列表直接传递给 printf():
然后将整个内容包装在宏中。
Ah, vsprintf() was the thing I was missing. I can use this to pass the variable argument list directly to printf():
Then wrap the whole thing in a macro.