c++ - Imprimir información en "modo de prueba" pero no en "ejecución normal"
testing printing (3)
La solución del preprocesador funcionará, pero puede ser molesto tener que reconstruir para cambiar de una a la otra. A menudo tomaré la decisión en tiempo de ejecución. Primero declaro:
static void do_nothing(const char *fmt, ...) { (void)fmt; }
extern void real_dprintf(const char *fmt, ...);
void (*dprintf)(const char *fmt, ...) = do_nothing;
Luego en el código de inicialización tengo
if (getenv("APPLICATION") && strstr(getenv("APPLICATION"), "dprintf"))
dprintf = real_dprintf;
De esta forma, puedo cambiar modos rápidamente cambiando el valor de una variable de entorno.
Estoy usando una aplicación en c ++ que usa una función dprintf especial para imprimir información, este es un ejemplo:
dprintf(verbose, "The value is: %d", i);
Lo que ocurre es que cuando defino verbose para propósitos de prueba, imprimo la información y cuando estoy trabajando en ejecución normal no la defino y no veo información inútil en la pantalla. Mi pregunta es ¿cómo puedo hacer esa función o implementar la misma idea ?.
#ifdef DEBUG
#define dprintf(format, ...) real_dprintf(format, __VA_ARGS__)
#else
#define dprintf
#endif
Aquí, real_dprintf () es la función "real" que se invoca, y dprintf () es simplemente una macro que envuelve la llamada.
Intento evitar usar las funciones var-arg c-style por dos razones principales:
- No son de tipo seguro, no pueden usar el operador <<
- No reconocen cuando se proporcionaron muy pocos o muchos argumentos
Hice una forma que funciona con boost::fusion
, que se da argumentos de una manera segura. Se repite sobre esos argumentos, imprimiéndolos cuando se encuentra un %
. Si se dieron demasiados o demasiados argumentos, se lanza una excepción.
Todavía hay un problema: las macros variadas aún no son estándar en C ++. Entonces, he hecho dos versiones. Uno que funciona con C ++ actual. Tienes que invocarlo usando
dprintf("name: %, value: %/n", ("foo", 42));
Entonces. La otra versión, que utiliza macros variadic, se puede usar definiendo un símbolo preprocesador, que le permite escribir
dprintf("name: %, value: %/n", "foo", 42);
Aquí está el código. El boost.fusion
proporciona más detalles para esto:
#include <boost/fusion/include/sequence.hpp>
#include <boost/fusion/include/make_vector.hpp>
#include <boost/fusion/include/next.hpp>
#include <stdexcept>
#include <iostream>
template<typename IterS, typename IterSeqE>
void print_vec(IterS b, IterS e, IterSeqE, IterSeqE) {
while(b != e) {
if(*b == ''%'') {
if(++b != e && *b == ''%'') {
std::cout << ''%'';
} else {
throw std::invalid_argument("too many ''%''");
}
} else {
std::cout << *b;
}
++b;
}
}
template<typename IterS, typename IterSeqB, typename IterSeqE>
void print_vec(IterS b, IterS e, IterSeqB seqb, IterSeqE seqe) {
while(b != e) {
if(*b == ''%'') {
if(++b != e && *b == ''%'') {
std::cout << ''%'';
} else {
std::cout << *seqb;
return print_vec(b, e, next(seqb), seqe);
}
} else {
std::cout << *b;
}
++b;
}
throw std::invalid_argument("too few ''%''");
}
template<typename Seq>
void print_vec(std::string const& msg, Seq const& seq) {
print_vec(msg.begin(), msg.end(), begin(seq), end(seq));
}
#ifdef USE_VARIADIC_MACRO
# ifdef DEBUG
# define dprintf(format, ...) /
print_vec(format, boost::fusion::make_vector(__VA_ARGS__))
# else
# define dprintf(format, ...)
# endif
#else
# ifdef DEBUG
# define dprintf(format, args) /
print_vec(format, boost::fusion::make_vector args)
# else
# define dprintf(format, args)
# endif
#endif
// test, using the compatible version.
int main() {
dprintf("hello %, i''m % years old/n", ("litb", 22));
}