admin管理员组文章数量:1434908
I'm developing an API looking like GLib logging.
My API can also disable these functions when the flag -DDEBUG
isn't passed to GCC.
That means, there are no residues in the binary, all these debug functions including their parameters aren't present in the executable if this flag isn't passed.
It works perfectly in C, because it's macro functions I can easily replace ;
Example in C
debug.h
#include <stdio.h>
#include <stdlib.h>
#include "term.h"
/**
* @brief Print something in debug mode
* @details No loglevel/context
* @param format
* @param ... Parameters for format
*/
#define printf_debug(fmt, ...)
#define LOG_NONE 0
#define LOG_FATAL 1
#define LOG_ERROR 2
#define LOG_WARNING 3
#define LOG_INFO 4
#define LOG_DEBUG 5
#define LOG_TRACE 6
#if (defined(DEBUG))
#undef printf_debug
#define printf_debug(format, ...) \
fprintf(stderr, " " format "\n", __FILE__, __func__, __LINE__, ##__VA_ARGS__)
#endif // (defined(DEBUG))
main.c
#include <debug/debug.h>
int main()
{
printf_debug("Hello world !"); // Show in any debug context
return 0;
}
If I compile without the flag -DDEBUG
, neither my macro function printf_debug()
nor the string "Hello" remains.
I would have like to do the same in C++ with the << operator (such as std::cout
works), but I can't manage << operator like I manage parameters in C.
Here's what I have tried ;
debug.hpp
#include <iostream>
#define LOG_UNDEFINED (-1)
#define LOG_NONE 0
#define LOG_FATAL 1
#define LOG_ERROR 2
#define LOG_WARNING 3
#define LOG_INFO 4
#define LOG_DEBUG 5
#define LOG_TRACE 6
namespace debug
{
#ifdef DEBUG
class debug_cout
: public std::ostream
{
public:
debug_cout(std::streambuf *sbuf)
: std::ios(sbuf), std::ostream(sbuf)
{}
~debug_cout() {}
};
debug_cout cout(int l) {
static int level = l;
return debug_cout(std::cout.rdbuf());
}
#else
class debug_cout
: public std::ostream
{
public:
debug_cout() {}
~debug_cout() {}
};
debug_cout cout(int l) {
return debug_cout();
}
#endif
}
main.cpp
#include <debug/debug.hpp>
int main() {
debug::cout(LOG_ERROR) << "Hello " << 3 << std::endl;
return 0;
}
It compiles correctly this way ;
Using -DDEBUG
flag, it outputs ;
Hello 3
Without -DDEBUG
, it outputs nothing, but there are residues in the executable. I see using objdump
my functions debug::cout()
remains and is called.
I have also tried using GCC optimization flag -O3
.
So my question ; Is it possible to ignore these instructions in C++ ? The ones having << operator.
Note: It's not an issue if I can't use namespace
Note 2: When I talk about residues I mean my function debug::cout()
remains in the executable in C++ and is executed (and it just does nothing).
I'm developing an API looking like GLib logging.
My API can also disable these functions when the flag -DDEBUG
isn't passed to GCC.
That means, there are no residues in the binary, all these debug functions including their parameters aren't present in the executable if this flag isn't passed.
It works perfectly in C, because it's macro functions I can easily replace ;
Example in C
debug.h
#include <stdio.h>
#include <stdlib.h>
#include "term.h"
/**
* @brief Print something in debug mode
* @details No loglevel/context
* @param format
* @param ... Parameters for format
*/
#define printf_debug(fmt, ...)
#define LOG_NONE 0
#define LOG_FATAL 1
#define LOG_ERROR 2
#define LOG_WARNING 3
#define LOG_INFO 4
#define LOG_DEBUG 5
#define LOG_TRACE 6
#if (defined(DEBUG))
#undef printf_debug
#define printf_debug(format, ...) \
fprintf(stderr, " " format "\n", __FILE__, __func__, __LINE__, ##__VA_ARGS__)
#endif // (defined(DEBUG))
main.c
#include <debug/debug.h>
int main()
{
printf_debug("Hello world !"); // Show in any debug context
return 0;
}
If I compile without the flag -DDEBUG
, neither my macro function printf_debug()
nor the string "Hello" remains.
I would have like to do the same in C++ with the << operator (such as std::cout
works), but I can't manage << operator like I manage parameters in C.
Here's what I have tried ;
debug.hpp
#include <iostream>
#define LOG_UNDEFINED (-1)
#define LOG_NONE 0
#define LOG_FATAL 1
#define LOG_ERROR 2
#define LOG_WARNING 3
#define LOG_INFO 4
#define LOG_DEBUG 5
#define LOG_TRACE 6
namespace debug
{
#ifdef DEBUG
class debug_cout
: public std::ostream
{
public:
debug_cout(std::streambuf *sbuf)
: std::ios(sbuf), std::ostream(sbuf)
{}
~debug_cout() {}
};
debug_cout cout(int l) {
static int level = l;
return debug_cout(std::cout.rdbuf());
}
#else
class debug_cout
: public std::ostream
{
public:
debug_cout() {}
~debug_cout() {}
};
debug_cout cout(int l) {
return debug_cout();
}
#endif
}
main.cpp
#include <debug/debug.hpp>
int main() {
debug::cout(LOG_ERROR) << "Hello " << 3 << std::endl;
return 0;
}
It compiles correctly this way ;
Using -DDEBUG
flag, it outputs ;
Hello 3
Without -DDEBUG
, it outputs nothing, but there are residues in the executable. I see using objdump
my functions debug::cout()
remains and is called.
I have also tried using GCC optimization flag -O3
.
So my question ; Is it possible to ignore these instructions in C++ ? The ones having << operator.
Note: It's not an issue if I can't use namespace
Note 2: When I talk about residues I mean my function debug::cout()
remains in the executable in C++ and is executed (and it just does nothing).
3 Answers
Reset to default 2Your non-logging debug_cout
shouldn't inherit from std::ostream
. Instead implement empty functions for streaming that does nothing. That should be easy for the compiler to optimize away:
class debug_cout {
public:
template <class T>
requires requires(T t) { std::cout << t; }
debug_cout& operator<<(T&&) {
return *this;
}
debug_cout& operator<<(std::ios_base& (*)(std::ios_base&)) {
return *this;
}
debug_cout& operator<<(std::ios& (*)(std::ios&)) { return *this; }
debug_cout& operator<<(std::ostream& (*)(std::ostream&)) {
return *this;
}
};
Demo
Is it possible to ignore these instructions in C++
Yes. if constexpr
can eliminate entire branches of code:
#ifdef DEBUG
# define DEBUG_COUT(level) if constexpr (0) {} else real_stream{level}
#else
# define DEBUG_COUT(level) if constexpr (1) {} else null_stream{level}
#endif
And use it like this:
DEBUG_COUT(5) << "Hello, " << 5 << " Worlds\n";
Live example: https://godbolt./z/7j6drn9ec
P.S. Different definitions of the same class depending on some macro? That's a recipe for wonderful bugs in case of linking wrong library/object. Don't do that.
#else
class debug_cout
: public std::ostream
Your NDEBUG
dummy object is an ostream. That's not nothing!
Even if the streambuf isn't connected to anything, that can change (and must therefore be checked) at runtime. You already know this, because you're setting the same streambuf up at runtime in the DEBUG
branch.
You want a type that does nothing, so just write that:
#else
class debug_cout {};
and you want it to work with stream insertion syntax, so write that:
template <class T>
debug_cout& operator<<(debug_cout& s, T&&)
{
return s;
}
本文标签: Ignore the use of a C function during compilation having operatorltltStack Overflow
版权声明:本文标题:Ignore the use of a C++ function during compilation having operator<< - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1745630133a2667220.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论