QDebug 的不换行使用技巧

在这里插入图片描述

简介

在Qt开发里,使用 qDebug() 来打印日志信息,是一件十分愉快的事情,很多类、容器都可以直接打印,十分方便,而且还实现了编码输出,在windows上使用msvc编译器,构建输出不会出现乱码,会觉得更加舒服。

但有时想要打印自己格式的信息,比如 打印一个数组时,qDebug() 会自动产生添加换行,把一个整体的信息给弄得支离破碎

int arr[] = {1,2,3};
for (int i = 0; i < sizeof(arr)/sizeof(int); ++i) {
	qDebug() << arr[i];
}
---
1
2
3

如果想打印成 数组 [1,2,3] 这种形式, 又该怎么办?

int arr[] = {1,2,3};
QString buf;
buf.append("数组 [ ");
for (int i = 0; i < sizeof(arr)/sizeof(int); ++i) {
	buf.append(std::to_string(arr[i])).append(", ");
}
buf.replace(buf.length()-2,2," ]");
qDebug() << buf;

用一个QString来包装下msg就ok了,这种方式也直接也明了,不过代码就不再简洁了,我只是想要看一下信息而已。

有人说用 printf 或者 std::cout 来打印,这又牵扯到编码问题,如果项目没引入Qt包,可以直接设置源码编码。

但如果使用了 Qt,就别想通过如下cmake语句设置执行编码,会报错

#################### 设置源码编码  ####################
add_compile_options("$<$<CXX_COMPILER_ID:MSVC>:/source-charset:utf-8>")
# add_compile_options("$<$<CXX_COMPILER_ID:MSVC>:/execution-charset:GBK>")
---报错信息---
D:\Project\cppstl\test\Main.cpp:1: error: In included file: static assertion failed: Error in C++ Standard Library usage.

问题在于解决qDebug() 的换行问题,咋越来越复杂啦??

qDebug() 宏

现在来大致看一下源码,会发现qDebug其实是一个QDebug对象,一个 QDebug 对象最终会添加一个 '\n' 换行符,并且在对象销毁时才会向设备打印,大概的代码逻辑如下:

--------------------------------------------------------------------------------
//消息日志上下文的宏定义
#ifdef QT_MESSAGELOGCONTEXT
  #define QT_MESSAGELOG_FILE static_cast<const char *>(__FILE__)
  #define QT_MESSAGELOG_LINE __LINE__
  #define QT_MESSAGELOG_FUNC static_cast<const char *>(Q_FUNC_INFO)
#else
  #define QT_MESSAGELOG_FILE nullptr
  #define QT_MESSAGELOG_LINE 0
  #define QT_MESSAGELOG_FUNC nullptr
#endif

//--------------------------------------------------------------------------------
//qDebug 的宏定义
#define qDebug QMessageLogger(QT_MESSAGELOG_FILE, QT_MESSAGELOG_LINE, QT_MESSAGELOG_FUNC).debug
  #define QT_MESSAGELOG_FILE nullptr
  #define QT_MESSAGELOG_LINE 0
  #define QT_MESSAGELOG_FUNC nullptr
//展开后 原来是构造出了一个 QMessageLogger 对象,并调用debug()方法
 QMessageLogger(nullptr,0,nullptr).debug()

//QMessageLogger 构造函数 ---------------------------------------------------------
Q_DECL_CONSTEXPR QMessageLogger(const char *file, int line, const char *function)
        : context(file, line, function, "default") {}

//QMessageLogger::debug() 方法 返回一个QDebug 对象-----------------------------------
QDebug QMessageLogger::debug() const
{
    QDebug dbg = QDebug(QtDebugMsg); // 这儿构造了一个QDebug 对象 dbg
    QMessageLogContext &ctxt = dbg.stream->context;
    ctxt.copyContextFrom(context);
    return dbg;
}

//信息类型枚举 ----------------------------------------------------------------
enum QtMsgType { QtDebugMsg, QtWarningMsg, QtCriticalMsg, QtFatalMsg, QtInfoMsg, QtSystemMsg = QtCriticalMsg };

//QDebug 构造函数 ----------------------------------------------------------------
inline QDebug(QtMsgType t) : stream(new Stream(t)) {}

//QDebug << 运算符 ---------------------------------------------------------------
inline QDebug &operator<<(const QString & t) { putString(t.constData(), uint(t.length())); return maybeSpace(); }

//QDebug::putString() 其实就是往内部的 QString buf里增加、转义、填充字符 -----------
void QDebug::putString(const QChar *begin, size_t length)
{
    if (stream->testFlag(Stream::NoQuotes)) {
        // no quotes, write the string directly too (no pretty-printing)
        // this respects the QTextStream state, though
        stream->ts.d_ptr->putString(begin, int(length));
    } else {
        // we'll reset the QTextStream formatting mechanisms, so save the state
        QDebugStateSaver saver(*this);
        stream->ts.d_ptr->params.reset();
        putEscapedString(stream->ts.d_ptr.data(), reinterpret_cast<const ushort *>(begin), int(length));
    }
}

//--------------------------------------------------------------------------------
// QDebug 对象被析构时,才会调用 qt_message_output
QDebug::~QDebug()
{
    if (stream && !--stream->ref) {
        if (stream->space && stream->buffer.endsWith(QLatin1Char(' ')))
            stream->buffer.chop(1);
        if (stream->message_output) {
            qt_message_output(stream->type,
                              stream->context,
                              stream->buffer);
        }
        delete stream;
    }
}

//qt_message_output 这个玩意又调用 qt_message_print---------------------------------
void qt_message_output(QtMsgType msgType, const QMessageLogContext &context, const QString &message)
{
    qt_message_print(msgType, context, message);
    if (isFatal(msgType))
        qt_message_fatal(msgType, context, message);
}
//qt_message_print 才实际向io设备打印 编码后的信息,也解决了乱码问题 ----------------------
//让人头疼的换行问题也在这儿 ------------------------------------------------------------
static void qt_message_print(QtMsgType msgType, const QMessageLogContext &context, const QString &message)
{
#ifndef QT_BOOTSTRAPPED
    Q_TRACE(qt_message_print, msgType, context.category, context.function, context.file, context.line, message);

    // qDebug, qWarning, ... macros do not check whether category is enabledgc
    if (msgType != QtFatalMsg && isDefaultCategory(context.category)) {
        if (QLoggingCategory *defaultCategory = QLoggingCategory::defaultCategory()) {
            if (!defaultCategory->isEnabled(msgType))
                return;
        }
    }
#endif

    // prevent recursion in case the message handler generates messages
    // itself, e.g. by using Qt API
    if (grabMessageHandler()) {
        const auto ungrab = qScopeGuard([]{ ungrabMessageHandler(); });
        auto oldStyle = msgHandler.loadAcquire();
        auto newStye = messageHandler.loadAcquire();
        // prefer new message handler over the old one
        if (newStye || !oldStyle) {
            (newStye ? newStye : qDefaultMessageHandler)(msgType, context, message);
        } else {
            (oldStyle ? oldStyle : qDefaultMsgHandler)(msgType, message.toLocal8Bit().constData());
        }
    } else {
        fprintf(stderr, "%s\n", message.toLocal8Bit().constData());
    }
}

使用 QDebug 对象来实现不换行的操作

从上述代码可以看到 一个 QDebug 对象 会打印一个"\n", 除非你自己实现并安装一个QtMessageHandler函数,具体实现参考 QtLogging 的帮助文档,略过。

或者利用 QDebug << 操作只是在缓存字符串,析构时才打印 msg+"\n"的特性,简单实现不换行的技巧

{
    // auto qdebug = qDebug();  // 这种兜兜转转,不利落
    auto qdebug = QDebug(QtDebugMsg);   // 这种直接一点,构造一个QDebug()对象
    qdebug << "数组 [";
    int arr[] = {1,2,3};
    for (int i = 0; i < sizeof(arr)/sizeof(int); ++i) {
        qdebug.nospace() << arr[i] << ",";
    }
    qdebug << "]";
    // qdebug.~QDebug(); 或者主动调用析构,或者等qdebug退出作用域自动析构
}
// 输出
数组 [ 1,2,3,]
  • 4
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值