C++對(duì)象指針無(wú)法進(jìn)行-n或+n [包含VS Code啟動(dòng)調(diào)試教程]
Gcc版本:gcc (Rev3, Built by MSYS2 project) 12.1.0
VS Code版本:
????????????????????????版本: 1.70.1 (system setup)
????????????????????????提交: 6d9b74a70ca9c7733b29f0456fd8195364076dda
????????????????????????日期: 2022-08-10T06:08:33.642Z
????????????????????????Electron: 18.3.5
????????????????????????Chromium: 100.0.4896.160
????????????????????????Node.js: 16.13.2
????????????????????????V8: 10.0.139.17-electron.0
????????????????????????OS: Windows_NT x64 10.0.22000
最近在學(xué) C++,發(fā)現(xiàn)對(duì)象數(shù)組指針無(wú)法進(jìn)行 + n 或 -n操作,如果進(jìn)行 +n或者 -n操作,那么輸出就會(huì)異常。
先說(shuō)解決辦法:使用++,--代替 +n 或 -n 操作。
Bug復(fù)現(xiàn)
1.定義一個(gè)類(lèi)
2.在堆上分配對(duì)象數(shù)組
3.給三個(gè)對(duì)象的成員變量賦值
4.打算用 for 循環(huán)輸出,所以直接對(duì)指針 -2,將指針復(fù)原
5.使用 for 輸出
很顯然,沒(méi)有得到我們想要的結(jié)果。這是為什么呢?
調(diào)試
通過(guò)觀察,發(fā)現(xiàn)輸出的?"葫蘆娃" 是最后一個(gè)初始化的對(duì)象成員變量,有沒(méi)有一種可能——指針沒(méi)有向后移動(dòng)兩個(gè)對(duì)象長(zhǎng)度。
1.配置默認(rèn)生成任務(wù)[單個(gè)源文件]
說(shuō)干就干,我們使用 VS Code 調(diào)試本程序。依次點(diǎn)擊 終端>配置默認(rèn)生成任務(wù) ,在下拉框選擇 C/C++:g++.exe 生成活動(dòng)文件

系統(tǒng)會(huì)幫我們自動(dòng)生成默認(rèn)配置:
并且在資源管理器的工作空間下自動(dòng)生成 tasks.json 文件

2.配置調(diào)試文件
點(diǎn)擊側(cè)邊欄的運(yùn)行和調(diào)試按鈕,然后點(diǎn)擊 創(chuàng)建launch.json 文件

在下拉欄中選擇 C++(GDB/LLDB)

點(diǎn)擊右下角的添加配置

在彈出的下拉欄中選擇 C/C++: (gdb) 啟動(dòng) 選項(xiàng)

系統(tǒng)會(huì)自動(dòng)生成調(diào)試器配置文件模板,我們需要修改幾個(gè)東西。

第一,在 "program":后輸入字符串?"${fileDirname}\\${fileBasenameNoExtension}.exe" ,${fileDirname} 表示當(dāng)前激活文件的目錄名稱(chēng),\\ 在windows平臺(tái)代表 / 文件夾分隔符,${fileBasenameNoExtension} 表示當(dāng)前激活文件的名字,不包括擴(kuò)展名。
第二,在?"miDebuggerPath":?后輸入你 gdb.exe 所在的完整目錄,這是你調(diào)試器的路徑。舉例:我的目錄如下

所以填寫(xiě):"miDebuggerPath":?"D:\\msys64\\mingw64\\bin\\gdb.exe"?,你也可以把 \\ 換成 /??"miDebuggerPath":?"D:/msys64/mingw64/bin/gdb.exe"?都是可以的。
第三,在這個(gè)花括號(hào)內(nèi),添加最后一個(gè)選項(xiàng) "preLaunchTask": 這個(gè)選項(xiàng)表示:在啟動(dòng)調(diào)試之前,先啟動(dòng)一個(gè)任務(wù);由于我們選擇的是啟動(dòng)調(diào)試,所以源文件需要提前編譯好,再將編譯好的文件進(jìn)行啟動(dòng)調(diào)試,而這個(gè)提前的任務(wù)就是我們剛才設(shè)置的默認(rèn)生成任務(wù)。

現(xiàn)在,打開(kāi) tasks.json 文件找到 "label",復(fù)制后面的字符串到 "preLaunchTask":后面。

3.調(diào)試
在開(kāi)始調(diào)試之前,先回到我們的源文件,還有幾件事沒(méi)做。
1.更改字符集;調(diào)試器的默認(rèn)編碼是 utf-8 , 如果以現(xiàn)在的字符集去生成可執(zhí)行文件,在調(diào)試輸出時(shí)將產(chǎn)生亂碼。點(diǎn)擊右下角狀態(tài)的字符集,我的默認(rèn)字符集是 GB 2312 ,現(xiàn)在點(diǎn)擊它

選擇通過(guò)編碼保存

在彈出的字符集中選擇 utf-8

2.設(shè)置斷點(diǎn)。只有設(shè)置斷點(diǎn),調(diào)試器才會(huì)根據(jù)斷點(diǎn)停止,否則直接完成運(yùn)行程序,那調(diào)試也無(wú)從說(shuō)起了。在 VS Code中設(shè)置斷點(diǎn)和 VS 中是一樣的:在行號(hào)的左邊,鼠標(biāo)左鍵單擊,出現(xiàn)紅色圓點(diǎn),就代表斷點(diǎn)已經(jīng)設(shè)置完成。

3.開(kāi)始調(diào)試。點(diǎn)擊左邊欄的 啟動(dòng)和調(diào)試 按鈕,現(xiàn)在可以看到我們配置的啟動(dòng)調(diào)試了。點(diǎn)擊小三角形,開(kāi)始調(diào)試。它將依次生成可執(zhí)行文件.exe,然后執(zhí)行啟動(dòng)調(diào)試。注意:必須在被激活的文件上執(zhí)行調(diào)試(也就是你想要調(diào)試的文件上)。

此時(shí)程序停在了斷點(diǎn)處:

調(diào)試面板位于屏幕上方中間處:

~@? 點(diǎn)擊最左邊的六個(gè)小點(diǎn)可以拖動(dòng)調(diào)試面板
~@? 第一個(gè)一個(gè)豎線挨著一個(gè)三角形的按鈕,表示繼續(xù)執(zhí)行程序按鈕,它的作用是執(zhí)行到下一個(gè)斷點(diǎn),再停止程序。
~@? 第二個(gè)按鈕,像跳過(guò)一個(gè)點(diǎn)的按鈕,表示跳過(guò)函數(shù)內(nèi)部執(zhí)行過(guò)程,如跳過(guò)?Aclass[0].say(); 函數(shù),直接運(yùn)行到第43 行。

~@? 第三個(gè)按鈕,一個(gè)豎向的箭頭指向一個(gè)點(diǎn),表示單步執(zhí)行,它的作用是,以精確的程序執(zhí)行步驟運(yùn)行程序,在調(diào)試過(guò)程中遇到函數(shù),則會(huì)進(jìn)入那個(gè)函數(shù)內(nèi)部,一步一步執(zhí)行每一行代碼,只有執(zhí)行完那個(gè)函數(shù)內(nèi)部的代碼才會(huì)回到上一層函數(shù)的棧上來(lái)。
~@? 第四個(gè)按鈕,一個(gè)點(diǎn)位于一個(gè)豎向向上箭頭的底部。表示單步跳出,能夠從函數(shù)內(nèi)部直接跳到上一層函數(shù)棧上來(lái)。
~@? 第五個(gè)按鈕,一個(gè)帶箭頭的圈圈,表示重啟調(diào)試過(guò)程。
~@? 第六個(gè)按鈕,一個(gè)正方形圖像,表示停止調(diào)試。
4.添加監(jiān)視。在左邊欄中可以看到本地變量的名稱(chēng)和地址:

右鍵點(diǎn)擊我們要監(jiān)視的變量?Aclass,在彈出的菜單中選擇 添加到監(jiān)視

在變量窗口下,就是監(jiān)視窗口。在 Aclass的左邊有一個(gè) > 按鈕,點(diǎn)擊它,可以展開(kāi)詳細(xì)的信息,比如該變量的成員信息,地址信息:

回到正題,我們要驗(yàn)證——使用地址 -n改變不了當(dāng)前地址。點(diǎn)擊單步執(zhí)行,監(jiān)視窗口刷新了變量信息,右鍵單擊變量名,點(diǎn)擊復(fù)制值

1)? 我們記錄第一次變量的地址信息:
2)? 運(yùn)行到 變量 ++ 之后,記錄第二次變量地址的信息。

地址:
3)? 記錄最后一次 變量 ++ 地址改變信息:
不難發(fā)現(xiàn)三個(gè)地址相差了 0x 10
4)? 記錄 變量 -2 時(shí)地址改變的信息:

地址:
通過(guò)對(duì)比,我們發(fā)現(xiàn)運(yùn)行 Aclass-2并不會(huì)改變變量的地址,問(wèn)題出在這。
我們將Aclass-2; 這行代碼換成兩行 Aclass--;然后再調(diào)試一次,發(fā)現(xiàn)地址變化出現(xiàn)了預(yù)期效果。
結(jié)果告訴我們,在現(xiàn)版本的C++中已經(jīng)不支持使用 -n、+n這種方法執(zhí)行地址操作了。使用++,--依舊有效。
源碼展示:
文章存在歧義是必然的,此時(shí)應(yīng)請(qǐng)?zhí)峁篻cc版本號(hào),VS code版本號(hào),供大家斟酌仔細(xì)分析。