qDebug 學習小結
在qtcentre中看到有網友問這樣一個問題:
Why this doesn't work? qDebug() << "Test" << std::endl;
- 第一反應:這兩個東西本來就不能這樣搭配使用啊。
- 第二反應:額,如何解釋這個問題呢?還真不知道
- 第三反應:...
std::cout<<std::endl;
在Qt中用了二三年C++了,還真沒想過C++中的這麼一個簡單的語句是怎麼工作的:
- 只知道std::endl等價於換行+flush
- 再一想,卻不知道endl是什麼東西了
函式指標
std::endl 是一個模板函式的函式指標
template <class charT, class traits> basic_ostream<charT,traits>& endl ( basic_ostream<charT,traits>& os );
看看GCC中的具體實現
template<typename _CharT, typename _Traits> inline basic_ostream<_CharT, _Traits>& endl(basic_ostream<_CharT, _Traits>& __os) { return flush(__os.put(__os.widen('/n'))); }
操作符過載
<< 原本是移位操作符,毫無疑問這兒是過載以後的:
typedef basic_ostream<_CharT, _Traits> __ostream_type; __ostream_type& operator<<(__ostream_type& (*__pf)(__ostream_type&)) { return __pf(*this); }
這樣以來我們就是它是怎麼工作的了。也知道下面兩個也就等價了
std::cout<<std::endl; std::endl(std::cout);
帶引數的操縱符?
std::endl、std::flush、std::hex等等都稱為 Manipulator。如前所述,他們都是函式指標。
除此之外,還有一些帶引數的 Manipulator,比如:
std::cout<<std::setw(8);
這又是神馬東西(反正不像是函式指標了)?
- 看看GCC的標頭檔案:
inline _Setw setw(int __n) { return { __n }; }
-
函式返回值是一個結構體_Setw 的物件
struct _Setw { int _M_n; };
-
同樣需要操作符<< 過載
template<typename _CharT, typename _Traits> inline basic_ostream<_CharT, _Traits>& operator<<(basic_ostream<_CharT, _Traits>& __os, _Setw __f) { __os.width(__f._M_n); return __os; }
qDebug
- 首先qDebug有兩個過載的函式:
void qDebug(const char *, ...); QDebug qDebug();
- 後者需要包含QDebug這個標頭檔案才能使用,大家都比較熟悉了。
-
其次,如果定義了巨集 QT_NO_DEBUG_OUTPUT ,qDebug將什麼都不做。這是因為:
#ifdef QT_NO_DEBUG_OUTPUT # define qDebug while(false)qDebug #endif
qInstallMsgHandler()
qInstallMsgHandler 設定的是一個靜態的函式指標變數(handler):
typedef void (*QtMsgHandler)(QtMsgType, const char *); static QtMsgHandler handler = 0; QtMsgHandler qInstallMsgHandler(QtMsgHandler h) { QtMsgHandler old = handler; handler = h; #if defined(Q_OS_WIN) && defined(QT_BUILD_CORE_LIB) if (!handler && usingWinMain) handler = qWinMsgHandler; #endif return old; }
qDebug 和這個東西是怎麼聯絡上的?
- 首先,引數可變的 qDebug 呼叫了 qt_message 函式:
void qDebug(const char *msg, ...) { va_list ap; va_start(ap, msg); // use variable arg list qt_message(QtDebugMsg, msg, ap); va_end(ap); }
- 然後藉助QString做個轉換,呼叫qt_message_output函式:
static void qt_message(QtMsgType msgType, const char *msg, va_list ap) { QByteArray buf; if (msg) buf = QString().vsprintf(msg, ap).toLocal8Bit(); qt_message_output(msgType, buf.constData()); }
- 在這個函式中
-
如果安裝有MsgHandler(即靜態的函式指標變數handler非0),則使用
- 如果未安裝,則輸出到標準出錯(注意:qDebug之所以換行是這兒引入的!)
-
void qt_message_output(QtMsgType msgType, const char *buf) { if (handler) { (*handler)(msgType, buf); } else { fprintf(stderr, "%s/n", buf); fflush(stderr); } ...
QDebug
我們似乎很少 (fix me)直接使用這個類,一般都是通過qDebug()生成一個物件來使用
QDebug qDebug() { return QDebug(QtDebugMsg); }
有意思的一點:這樣使用時,只有當QDebug析構時,才會將內容輸出(看到前面提到的qt_message_output了吧?):
inline ~QDebug() { if (!--stream->ref) { if(stream->message_output) { qt_message_output(stream->type, stream->buffer.toLocal8Bit().data()); } delete stream; } }
流操作符
同一開始提到的C++標準庫中的流操作符一樣,在這兒我們也可以使用不帶引數的和帶引數的流操作符(注意endl和std::endl的區別):
qDebug()<<qSetFieldWidth(8)<<800<<endl;
- 首先,肯定有相應的過載操作符:
class QDebug { ... inline QDebug &operator<<(QTextStreamFunction f) { stream->ts << f; return *this; } inline QDebug &operator<<(QTextStreamManipulator m) { stream->ts << m; return *this; }
- 然後有相應的函式指標型別 和 類型別
typedef QTextStream & (*QTextStreamFunction)(QTextStream &); class QTextStreamManipulator { ... };
QDebug::space()等
QDebug的三個成員函式看Manual總覺得暈乎乎的,看程式碼就很直觀了
class QDebug { ... inline QDebug &space() { stream->space = true; stream->ts << ' '; return *this; } inline QDebug &nospace() { stream->space = false; return *this; } inline QDebug &maybeSpace() { if (stream->space) stream->ts << ' '; return *this; }
參考
- The C++ Standard Library: A Tutorial and Reference
-
http://www.cppblog.com/yindf/archive/2009/05/12/80382.html
- Qt Manual 及 原始碼
相關文章
- 學習小結
- vue 學習小結Vue
- JavaScript學習小結JavaScript
- NFS學習小結NFS
- 小程式學習總結
- git學習小總結Git
- CommonsChunkPlugin學習小結Plugin
- 整合學習原理小結
- Spring 學習小結Spring
- HTML5 學習小結HTML
- Activiti 學習筆記 小結筆記
- Thrift-java學習小結Java
- awk指令碼學習小結指令碼
- Android:Sqlitedatabase學習小結AndroidSQLiteDatabase
- WebPack持久快取學習小結Web快取
- Vue1.0學習小結2Vue
- 《angular 權威教程》學習小結Angular
- 不確定估計學習小結
- Nginx支援WebSocket反向代理-學習小結NginxWeb
- redis執行緒模型-學習小結Redis執行緒模型
- 學習vue第一階段小結Vue
- Android學習之 WebView使用小結AndroidWebView
- 7.15--7.19學習小結
- 【C#學習之辨析小總結】C#
- Nginx code 常用狀態碼學習小結Nginx
- 跟小師父學習QTP後的總結QT
- 軟體測試工具QTP學習小結QT
- 前端學習小結(一)—基礎入門篇前端
- RMAN學習小結1:不完全恢復
- cJSON學習及簡單應用小結JSON
- 【資料結構】第六章學習小結--- 圖資料結構
- 學習git以及github自己的一點小總結:Github
- 2020-10-28 學習小結(七)
- 2020-10-20 學習小結(四)
- Activiti 學習筆記一到六小結筆記
- 整合學習之Adaboost演算法原理小結演算法
- SQLite資料庫學習小結——Frameworks層實現SQLite資料庫Framework
- 條件編輯及宏定義學習小結