C++調(diào)試記錄與心得分享
之前開(kāi)發(fā)用Linux C比較多,C++中的STL 容器基本沒(méi)有接觸過(guò)。最近在學(xué)習(xí)C++,平時(shí)用到c++ 17中的部分新特性,下面就簡(jiǎn)單分享下自己C++的學(xué)習(xí)流程。
一、環(huán)境搭建
本人使用的是CentOS 7系統(tǒng),該系統(tǒng)默認(rèn)的g++版本不支持c++17的新特性。所以,首先需要做的就是升級(jí)新版本的g++。
1.到ftp://ftp.mirrorservice.org/sites/sourceware.org/pub/gcc/releases/網(wǎng)站上選擇支持c++17的gcc版本,并使用wget下載到Linux系統(tǒng)中:wget ftp://ftp.mirrorservice.org/sites/sourceware.org/pub/gcc/releases/gcc-7.1.0/gcc-7.1.0.tar.bz2
2.安裝編譯gcc需要的依賴(lài)包 sudo yum install gmp-devel mpfr-devel libmpc-devel -y
3.解壓gcc壓縮包到temp文件夾 tar -jxf gcc-7.1.0.tar.bz2 -C temp
4.進(jìn)入到temp/gcc目錄下,執(zhí)行 gcc ./configure --enable-checking=release --enable-languages=c,c++ --disable-multilib && make 進(jìn)行g(shù)cc的編譯(這個(gè)步驟耗時(shí)較長(zhǎng))
5.安裝新版gcc sudo make install
6.由于在./configure階段未指定安裝路徑,那么新版的gcc的默認(rèn)安裝位置就是/usr/local/目錄下,修改標(biāo)準(zhǔn)庫(kù)的軟連接使其指向新版本的標(biāo)準(zhǔn)庫(kù) sudo ln -sf /usr/local/lib64/libstdc++.so.6.0.23 /lib64/libstdc++.so.6
7.需要使用c++17的特性時(shí),需要在Makefile的CXXFLAGS變量中添加 -std=c++17
gdb默認(rèn)情況下是不支持c++容器輸出的,不過(guò)在gdb 7.0版本之后,可以通過(guò)添加插件的方式來(lái)支持c++容器輸出
1.檢查gdb版本 gdb --version, (如果版本號(hào)低于7.0就不用往下看了)
2.在當(dāng)前用戶(hù)的home目錄中(如/home/sxhlinux)下載 插件代碼 svn co svn://gcc.gnu.org/svn/gcc/trunk/libstdc++-v3/python (沒(méi)有svn的,需要通過(guò) sudo yum install svn -y 安裝)然后執(zhí)行mv python .gdb_stl 將該文件夾重命名(使其隱藏)
3.執(zhí)行 vim ~/.gdbinit,編輯gdb配置文件,添加如下內(nèi)容
add-auto-load-safe-path /usr/local/lib64/libstdc++.so.6.0.23-gdb.py #文件的版本號(hào),根據(jù)這個(gè)目錄中的實(shí)際文件版本號(hào)確定
import sys
sys.path.append("/usr/local/share/gcc-7.1.0/python")
sys.path.insert(0, '/home/sxhlinux/.gdb_stl') #注:將第二個(gè)參數(shù)中的路徑改成自己的.gdb_stl文件夾路徑
from libstdcxx.v6.printers import register_libstdcxx_printers
register_libstdcxx_printers (None)
end
二、gdb 調(diào)試示例
1.下面的代碼是將帶有數(shù)字特征的分詞(用unorder_map保存),按照一定的規(guī)則(分詞的數(shù)字特征)進(jìn)行合并
#include <iostream>
#include <cstdlib>
#include <map>
#include <unordered_map>
using namespace std;
template <typename T1, typename T2>
bool merge_tokens(T1 &target, const T2 &rules)
{
auto pre = target.begin();
for (auto token = target.begin(); token != target.end(); ) {
if (pre == token) {
token ++;
continue;
}
auto range = rules.equal_range(pre->second);
auto it = range.first;
for (; it != range.second; it++) {
if (it->second == token->second) {
break;
}
}
if (it == range.second) {
pre = token;
token ++;
}
else {
pre->first += token->first;
// target.insert(std::make_pair<typename T1::key_type, typename T1::mapped_type>(pre->first + token->first, 16));
pre->second = 16;
token = target.erase(token);
pre = token;
}
}
}
int main ( int argc, char *argv[] )
{
unordered_map<string, size_t> tokens = {{"def", 22}, {"ghi", 100}, {"abc", 22}};
unordered_multimap<size_t, size_t> rules = {{22, 100}, {100, 22}, {1, 38}};
merge_tokens(tokens, rules);
return EXIT_SUCCESS;
} /* ---------- end of function main ---------- */
2. 編譯該文件,提示 31行
test.cpp:31:15: error: passing ‘const std::__cxx11::basic_string<char>' as ‘this' argument discards qualifiers [-fpermissive]
pre->first += token->first;
~~~~~~~~~~~^~~~~~~~~~~~~~
/usr/local/include/c++/7.1.0/bits/basic_string.h:1122:7: note: in call to ‘std::__cxx11::basic_string<_CharT, _Traits, _Alloc>& std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::operator+=(const std::__cxx11::basic_string<_CharT, _Traits, _Alloc>&) [with _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>]'
operator+=(const basic_string& __str)
^~~~~~~~
根據(jù)錯(cuò)誤提示:string 的運(yùn)算符 += 要求參數(shù)是一個(gè) const string類(lèi)型(作為右值,非const類(lèi)型也可以作為const類(lèi)型的參數(shù)使用),返回值是一個(gè)string類(lèi)型。再看 出錯(cuò)的語(yǔ)句 pre->first += token->first; 根據(jù)mian函數(shù)中的tokens的定義,token和pre的first成員都應(yīng)該是string而不是const string。
3.將報(bào)錯(cuò)的這一行注釋掉,然后用gdb查看下pre->first和token->first的具體類(lèi)型。具體如下
(gdb) whatis target type = std::unordered_map<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, unsigned long> & (gdb) whatis target.begin() type = std::unordered_map<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, unsigned long, std::hash<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::equal_to<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, unsigned long> > >::iterator (gdb) whatis pre type = std::__detail::_Node_iterator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, unsigned long>, false, true>
根據(jù)上面顯示的,target兩個(gè)參數(shù)類(lèi)型確實(shí)和定義的一樣,string和unsigned long;target.begin()類(lèi)型說(shuō)明中的std::allocator的模板參數(shù)pair的第一個(gè)參數(shù)為 string const,說(shuō)明在創(chuàng)建unordered_map時(shí),key的類(lèi)型為const string而不是string(猜測(cè)這跟map與key相關(guān)的只有增加、刪除而沒(méi)有修改操作有關(guān))。因?yàn)閍llocator在申請(qǐng)空間時(shí),已經(jīng)隱式的將string轉(zhuǎn)成了const string,所以,pre->first的類(lèi)型是const string而不是string(也就無(wú)法進(jìn)行+=,=等相關(guān)操作)。
4.根據(jù)第三步的分析結(jié)果,要實(shí)現(xiàn)合并元素的效果,只能是將合并后的值作為一個(gè)新的pair插入到原來(lái)的map中,然后將原來(lái)的兩個(gè)pair刪除。代碼如下:
target.insert(std::make_pair<typename T1::key_type, typename T1::mapped_type>(pre->first + token->first, 16)); target.erase(pre); token = target.erase(token); pre = token;
三、總結(jié)
很多時(shí)候我們遇到問(wèn)題首先想到的是將錯(cuò)誤復(fù)制下來(lái),然后粘貼到google搜索框中,漫無(wú)目的的去尋找答案,而不是仔細(xì)分析查看gcc給出的錯(cuò)誤提示。跟我的經(jīng)驗(yàn),很多時(shí)候gcc給出的提示相當(dāng)明顯,認(rèn)真仔細(xì)閱讀大部分可以很快找出解決方案,剩余的一部分棘手問(wèn)題可以借助搜索引擎(PS:當(dāng)搜索英文提示時(shí),如果沒(méi)有g(shù)oogle,可以使用英文版的必應(yīng),效果也不錯(cuò))
- Linux搭建C++開(kāi)發(fā)調(diào)試環(huán)境的方法步驟
- c++代碼調(diào)試方式的幾點(diǎn)建議
- 解決vscode下調(diào)試c/c++程序一閃而過(guò)的問(wèn)題(Windows)
- vscode C++遠(yuǎn)程調(diào)試運(yùn)行(學(xué)習(xí)C++用)
- vscode配置遠(yuǎn)程開(kāi)發(fā)環(huán)境并遠(yuǎn)程調(diào)試運(yùn)行C++代碼的教程
- VSCode遠(yuǎn)程開(kāi)發(fā)調(diào)試服務(wù)器c/c++代碼
- ubunt18.04LTS+vscode+anaconda3下的python+C++調(diào)試方法
- C++運(yùn)算符重載實(shí)例代碼詳解(調(diào)試環(huán)境 Visual Studio 2019)
- 詳解AndroidStudio3.0開(kāi)發(fā)調(diào)試安卓NDK的C++代碼
- 詳解C++的反調(diào)試技術(shù)與繞過(guò)手法
相關(guān)文章
C語(yǔ)言超細(xì)致講解循環(huán)語(yǔ)句
我們說(shuō)到當(dāng)滿(mǎn)足特定條件時(shí),就會(huì)執(zhí)行if語(yǔ)句或者switch語(yǔ)句后面的語(yǔ)句,否則不執(zhí)行,但是這只能執(zhí)行一次,在日常生活中,有些事情是需要重復(fù)去做的,C語(yǔ)句就為此引入了循環(huán)語(yǔ)句。所以今天繼續(xù)為大家分享C語(yǔ)言循環(huán)家族2022-05-05
C語(yǔ)言學(xué)習(xí)之柔性數(shù)組詳解
結(jié)構(gòu)體的最后一個(gè)元素允許是未知大小的數(shù)組,這就叫柔性數(shù)組。這篇文中主要為大家詳細(xì)介紹了C語(yǔ)言中柔性數(shù)組的相關(guān)知識(shí),需要的可以了解一下2023-03-03
C語(yǔ)言數(shù)據(jù)結(jié)構(gòu)系列之樹(shù)的概念結(jié)構(gòu)和常見(jiàn)表示方法
本章將正式開(kāi)啟數(shù)據(jù)結(jié)構(gòu)中?“樹(shù)”?部分的講解,本章將介紹樹(shù)的概念和結(jié)構(gòu),以及樹(shù)的表示方法,感興趣的朋友進(jìn)來(lái)看看吧2022-02-02
深度解析C語(yǔ)言中數(shù)據(jù)的存儲(chǔ)
本文詳細(xì)介紹了C語(yǔ)言中數(shù)據(jù)的存儲(chǔ),文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-05-05
c++函數(shù)指針和回調(diào)函數(shù)示例
這篇文章主要介紹了c++函數(shù)指針和回調(diào)函數(shù)示例,需要的朋友可以參考下2014-05-05

