Reputation: 2436
In Qt we can use the qDebug - and similar - macros for logging purposes. To organize the output we can define and use QLoggingCategories, together with the qCDebug macro.
The documentation tells us:
The macro expands to code that checks whether QLoggingCategory::isDebugEnabled() evaluates to true. If so, the stream arguments are processed and sent to the message handle
We do so by using the category using the Q_LOGGING_CATEGORY
. Consider the following minimal example:
#include <QCoreApplication>
#include <QDebug>
#include <QLoggingCategory>
Q_LOGGING_CATEGORY(cat, "cat")
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
qCDebug(cat) << "Hello World!";
return a.exec();
}
I noticed, that I can omit the C
, providing me with the following line:
qDebug(cat) << "Hello World!";
.
When executed, both lines give the same output:
cat: Hello World
I can also set QT_LOGGING_RULES
to cat=false
to turn of the message - in both variants.
Why would I use qCDebug over qDebug if the result is effectively the same?
Upvotes: 3
Views: 4172
Reputation: 2436
Looking at the code for both Macros shows the differences:
qDebug():
#define qDebug QMessageLogger(QT_MESSAGELOG_FILE, QT_MESSAGELOG_LINE, QT_MESSAGELOG_FUNC).debug
qCDebug():
# define qCDebug(category, ...) \
for (bool qt_category_enabled = category().isDebugEnabled(); qt_category_enabled; qt_category_enabled = false) \
QMessageLogger(QT_MESSAGELOG_FILE, QT_MESSAGELOG_LINE, QT_MESSAGELOG_FUNC, category().categoryName()).debug(__VA_ARGS__)
So the main difference is, that qCDebug(cat)
will check wether the category is enabled, before creating a QMessageLogger instance. If we use the qDebug()
macro, an overloaded function with a QLoggingCategory argument exists, I suppose for convenience? This function will perform the check only after the QMessageLogger was created.
I setup a simple benchmark to see the performance difference this makes - code below. Keeping the message length the same for all tests, I had the following results (numbers in brackets show the number of iterations, value is average time per iteration in msec):
+----------+---------------+-------------------+--------+
| category | qDebug | qCDebug | Factor |
+----------+---------------+-------------------+--------+
| enabled | 0.031(2048) | 0.024(4096) | 1.29 |
| disabled | 0.00077(4096) | 0.000016(4194304) | 48.0 |
+----------+---------------+-------------------+--------+
Exact numbers varied, of course, but the overall image stayed the same. If debug output for the category is enabled, both macros perform more or less the same, while if the category is disabled, using qCDebug
will be about ten to a hundred times faster than qDebug
. So the verdict should be to always use qCDebug when working with categories, as the documentation suggests, though the difference will probably only be noticeable if you produce a lot of (disabled) output.
Test Code for verification below:
Q_LOGGING_CATEGORY(test, "test")
class DebugBM: public QObject
{
Q_OBJECT
private slots:
void xdebugEnabled()
{
QBENCHMARK {
qDebug(test) << "Test.";
}
}
void cDebugEnabled()
{
QBENCHMARK {
qCDebug(test) << "Test.";
}
}
void xdebugDisable()
{
QLoggingCategory::setFilterRules("test.debug=false");
QBENCHMARK {
qDebug(test) << "Test.";
}
}
void cDebugDisable()
{
QLoggingCategory::setFilterRules("test.debug=false");
QBENCHMARK {
qCDebug(test) << "Test.";
}
}
};
QTEST_MAIN(DebugBM)
#include "DebugBM.moc"
Upvotes: 4