bug起源
最近在做解析二進制文件的工作,我的做法是寫一個繼承自ifstream的類然后封裝一些函數(shù)以便于讀取,譬如readUint32(), readHexString()等等。然后發(fā)現(xiàn)一個很隱蔽的bug........
bug簡述
在讀取一個數(shù)據(jù)時,該數(shù)據(jù)以00H結(jié)尾,我調(diào)用自己的函數(shù)返回一個string,請看下面簡化的代碼段:
include <iostream>
include <string>
using namespace std;
int main()
{
string str{ "test.aaa..ddd.bbb" };
str.push_back(0x00);
cout << str <<endl;
}
此時的輸出會是什么呢?
加和不加沒區(qū)別?非也!你去掉代碼里的 endl就會發(fā)現(xiàn)尾部還有一個“空格”。于是乎,
if (str == "test.aaa..ddd.bbb")
>_<;
是不會被執(zhí)行的。。
不止如此
00H這個字符的特殊性在于, 它會使 如下代碼
if (str == "test.aaa..ddd.bbb ") // 多一個空格
_;
if (str == "test.aaa..ddd.bbb\0")
(;
// 以及
if (str + " " == "test.aaa..ddd.bbb")
QAQ;
同樣不被執(zhí)行。
原因
上面提到“空格”一詞時,加上了引號,因為它并非我們常說的空格。ascii碼表里00H 和32H的字符形式都是空白,而32H則是我們鍵盤上敲空格鍵敲出來的。即,執(zhí)行如下代碼:
cout << (int)(' ');
則得到 32。
最后一個疑惑是,ascii碼表上 00H也可以用轉(zhuǎn)義字符代替,那為何
str == "test.aaa..ddd.bbb\0"
的值是0,然而,如下代碼段
string str{ "test.aaa..ddd.bbb" };
string yastr{ str };
str.push_back(0x00);
yastr.push_back('\0');
卻會使 yastr 和str相等呢?
yastr == str ----> 1
我的實驗環(huán)境是vs2015,這樣的結(jié)果可能是取決于編譯器(string == 操作的實現(xiàn)),也可能是c++認(rèn)為字符字面量后面加\0沒有實際的意義,后者是比較顯然的。
總體來說今天的bug之旅以及反思都是愉快的。雖然有收獲……但是……下次別再讓我碰到你!