C++ std::string 轉 std::vector<char> 的 2 種方法

本篇 ShengYu 介紹 C++ std::stringstd::vector<char> 的方法,

以下 C++ std::stringstd::vector<char> 的 2 種方法分別是,

  • 使用 vector range constructor
  • 使用 std::copy()

那我們就開始吧!

使用 vector range constructor

C++ std::stringstd::vector<char> 可以使用 vector 建構子中的 range constructor,方法如下,

cpp-string-to-vector-char.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// g++ cpp-string-to-vector-char.cpp -o a.out
#include <iostream>
#include <string>
#include <vector>

int main() {
std::string s = "Hello World";
std::vector<char> v(s.begin(), s.end());

for (int i = 0; i < v.size(); i++) {
std::cout << v[i];
}

return 0;
}

輸出如下,

1
Hello World

使用 std::copy()

另一種 C++ std::stringstd::vector<char> 可以使用 std::copy(),首先 vector 要配置好 string 長度的大小,之後再用 std::copy(),前兩個參數是指定複製的範圍,第三個參數是複製到哪裡,

cpp-string-to-vector-char2.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// g++ cpp-string-to-vector-char2.cpp -o a.out
#include <iostream>
#include <string>
#include <vector>

int main() {
std::string s = "Hello World";
std::vector<char> v(s.length());
std::copy(s.begin(), s.end(), v.begin());

for (int i = 0; i < v.size(); i++) {
std::cout << v[i];
}

return 0;
}

輸出如下,

1
Hello World

std::copy() 還可以使用 std::back_inserter 將複製的資料在容器的尾端插入,std::back_inserter 會在內部互叫 push_back,所以 vector 一開始不用預先分配好 size,範例如下,但是以效能來說,前述例子預先分配好 size 會比較好,也不會有過多的預留空間,

cpp-string-to-vector-char3.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// g++ cpp-string-to-vector-char3.cpp -o a.out
#include <iostream>
#include <string>
#include <vector>

int main() {
std::string s = "Hello World";
std::vector<char> v;
std::copy(s.begin(), s.end(), std::back_inserter(v));

for (int i = 0; i < v.size(); i++) {
std::cout << v[i];
}

return 0;
}

輸出同上。

以上就是 C++ std::stringstd::vector<char> 的 2 種方法的介紹,
如果你覺得我的文章寫得不錯、對你有幫助的話記得 Facebook 按讚支持一下!

其他參考
c++ - How to copy std::string into std::vector<char>? - Stack Overflow
https://stackoverflow.com/questions/8263926/how-to-copy-stdstring-into-stdvectorchar
Convert a string to a vector of chars in C++
https://www.techiedelight.com/convert-string-vector-chars-cpp/

其它相關文章推薦
C/C++ 新手入門教學懶人包
C++ std::vector<char> 轉 std::string 的 2 種方法
C/C++ 整數轉字串的方法與範例
C++ virtual 的兩種用法
C/C++ 字串反轉 reverse
C/C++ call by value傳值, call by pointer傳址, call by reference傳參考 的差別

Shell Script 判斷目錄資料夾是否存在

本篇 ShengYu 介紹 Shell Script 判斷目錄資料夾是否存在的用法與範例。

以下 Shell Script 判斷目錄資料夾是否存在的用法介紹將分為這幾部份,

  • Shell Script 判斷目錄資料夾是否存在
  • Shell Script 判斷多個目錄資料夾是否存在

那我們開始吧!

Shell Script 判斷目錄資料夾是否存在

這邊示範用 Shell Script 來判斷 myfolder 目錄資料夾是否存在,判斷目錄資料夾要用 -d,如下範例,要注意 -d 前有個空格,因為使用 if 條件判斷語法 [ ] 中括號的兩端內側必須要有一個空白字元,

1
2
3
4
5
if [ -d myfolder ]; then
echo "Yes"
else
echo "No"
fi

判斷檔案是否存在則是要用 -f

Shell Script 判斷多個目錄資料夾是否存在

這邊示範用 Shell Script 來判斷多個目錄資料夾是否存在,如果是要判斷兩個目錄資料夾都同時存在的話,可以用 && 連接條件式,範例如下,

1
2
3
4
5
if [ -d myfolder1 ] && [ -d myfolder2 ]; then
echo "Yes"
else
echo "No"
fi

如果要用 Shell Script 來判斷兩個目錄資料夾任一個目錄資料夾存在的話,可以用 || 連接條件式,範例如下,

1
2
3
4
5
if [ -d myfolder1 ] || [ -d myfolder2 ]; then
echo "Yes"
else
echo "No"
fi

如果要判斷 3 個目錄資料夾或 3 個以上的目錄資料夾是否同時存在,程式碼通常會比較長,
這時適時地換行就會比較好維護程式碼,範例如下,

1
2
3
4
5
6
7
if [ -d myfolder1 ] && 
[ -d myfolder2 ] &&
[ -d myfolder3 ]; then
echo "Yes"
else
echo "No"
fi

以上就是 Shell Script 判斷目錄資料夾是否存在的用法與範例介紹,
如果你覺得我的文章寫得不錯、對你有幫助的話記得 Facebook 按讚支持一下!

其它相關文章推薦
如果你想學習 Shell Script 相關技術,可以參考看看下面的文章,
Shell Script 判斷檔案是否存在
Shell Script 新手入門教學
Shell Script 四則運算,變數相加、相減、相乘、相除
Shell Script if 條件判斷
Shell Script for 迴圈
Shell Script while 迴圈
Shell Script 讀檔,讀取 txt 文字檔

Android adb reverse 通訊埠轉發用法教學

本篇 ShengYu 介紹 Android 的 adb reverse 通訊埠轉發的功能,adb reverse 的功能是轉發 Android 裝置上某個埠號 (port) 資料到 PC 電腦的某個埠號 (port),例如:下列 adb reverse 指令就是將 Android Device 的 port 10000 收到的資料,轉發給到 PC 端的 port 20000,

1
adb reverse tcp:10000 tcp:20000

Android 5.0 及以上才支援使用 adb reverse 指令,且 adb 要 1.0.32 之後的版本才支援。

通常在 PC 端會啟動一個 server 程式,而 Android Device 的 client 程式想要連到 PC 端的 server,除了使用 ip 的方式連線以外,沒有 ip 的話,還可以利用 USB 連線的方式,也就是透過 adb reverse 轉發 port,如此一來 Android Device 的 client 程式就可以連上 PC 端的 server 程式,

adb reverse 執行完後可以使用 adb reverse --list 查看轉發列表,或者用 adb reverse --remove-all 移除全部,

1
2
$ adb reverse --list
XX00X0000000 tcp:10000 tcp:20000

如果要移除轉發的話,就這樣下,

1
adb reverse --remove tcp:10000

以上就是 Android adb reverse 通訊埠轉發用法教學介紹,
如果你覺得我的文章寫得不錯、對你有幫助的話記得 Facebook 按讚支持一下!

相關主題
Android adb forward 通訊埠轉發用法教學
Android adb 基本用法教學
Android adb 同步時間/設定時間
Android adb shell input 事件用法
Anddroid VS Code 遠端除錯教學

LLDB 除錯教學

本篇 ShengYu 介紹 LLDB 除錯教學,LLDB Debugger 是 LLVM 專案的除錯元件。在使用 Debugger 時可以單步執行、執行到中斷點、查看變數內容、印出呼叫堆疊等等功能,是程式設計師的常用工具,以下將會介紹編譯完 C/C++ 程式後怎麼使用 LLDB 來替 C/C++ 程式偵錯。

以下 LLDB 除錯教學的內容大概分為這幾部分,

  • clang/clang++ 編譯 C/C++ 程式
  • LLDB 進行除錯

那我們開始吧!

clang/clang++ 編譯 C/C++ 程式

我的桌機環境為 Ubuntu 16.04,以下為一個簡單的 C/C++ 程式,使用 clang++ main.cpp -g -o a.out 進行編譯,編譯成功後會產生 a.out 執行檔,-g 表示帶有除錯資訊,這邊當然也可以使用 gcc/g++ 去編譯 C/C++ 程式 (g++ main.cpp -g -o a.out),gcc/g++ 編譯後的程式 LLDB 也可以進行除錯,

main.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// clang++ main.cpp -g -o a.out
#include <iostream>
#include <string>

int main() {
std::string s = "hello world";

int sum = 0;
for (int i = 0; i < 5; i++) {
sum += i;
}

std::cout << s << "\n";
std::cout << "sum=" << sum << "\n";
std::cout << "end\n";

return 0;
}

程式輸出如下,

1
2
3
hello world
sum=10
end

LLDB 進行除錯

接著使用 lldb 指令對 a.out 進行除錯,執行 lldb ./a.out 指令進入 lldb 交互介面,

1
2
3
4
$ lldb ./a.out 
(lldb) target create "./a.out"
Current executable set to './a.out' (x86_64).
(lldb)

輸入 b main.cpp:14 插入中斷點在 main.cpp 的 14 行,

1
2
3
(lldb) b main.cpp:14
Breakpoint 1: where = a.out`main + 188 at main.cpp:14, address = 0x0000000000400c2c
(lldb)

輸入 b 印出目前設定的中斷點,這個指令跟 gdb 有所不同,

1
2
3
4
5
6
(lldb) b
Current breakpoints:
1: file = 'main.cpp', line = 14, exact_match = 0, locations = 1
1.1: where = a.out`main + 188 at main.cpp:14, address = a.out[0x0000000000400c2c], unresolved, hit count = 0

(lldb)

按下 r 開始執行,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
(lldb) r
Process 24479 launched: './a.out' (x86_64)
hello world
Process 24479 stopped
* thread #1, name = 'a.out', stop reason = breakpoint 1.1
frame #0: 0x0000000000400c2c a.out`main at main.cpp:14
11 }
12
13 std::cout << s << "\n";
-> 14 std::cout << "sum=" << sum << "\n";
15 std::cout << "end\n";
16
17 return 0;
(lldb)

再次輸入 b 印出目前設定的中斷點,可以看到中斷點被觸發幾次,

1
2
3
4
5
6
(lldb) b
Current breakpoints:
1: file = 'main.cpp', line = 14, exact_match = 0, locations = 1, resolved = 1, hit count = 1
1.1: where = a.out`main + 188 at main.cpp:14, address = 0x0000000000400c2c, resolved, hit count = 1

(lldb)

接著按 c 繼續執行直到程式結束,

1
2
3
4
5
6
(lldb) c
Process 24479 resuming
sum=10
end
Process 24479 exited with status = 0 (0x00000000)
(lldb)

以下為 lldb 常用的指令,
r:run 開始執行
c:continue 繼續執行
b main.cpp:14:設定中斷點
b:印出目前設定的中斷點(這個指令跟 gdb 有所不同)
po <變數名稱>:印出目前變數的值,例如:po sum
bt:backtrace 印出程式呼叫的堆疊
q:quit 離開

以上就是 LLDB 除錯教學介紹,
如果你覺得我的文章寫得不錯、對你有幫助的話記得 Facebook 按讚支持一下!

其他參考
LLDB 玩樂筆記. 最近在寫 uTensor 的 CNN Demo 文章,code 是可以… | by Dboy Liao | Medium
https://dboyliao.medium.com/lldb-%E7%8E%A9%E6%A8%82%E7%AD%86%E8%A8%98-f5f5d5ed89ff

相關主題
gdb 除錯教學
gdbserver 遠端除錯教學

gdbserver 遠端除錯教學

本篇 ShengYu 介紹使用 gdbserver 來遠端除錯教學,gdb 可以透過網路對遠端的程式進行除錯,需要遠端執行 gdbserver 以及搭配本地端 gdb 一起使用,而 gdbserver 是 server 的角色,而 gdb 是 client 的角色,一旦 gdb 連上遠端的 gdbserver 後,之後就使用 gdb 進行除錯,跟平常的 gdb 使用上沒有差異,我的桌機環境為 Ubuntu 16.04,

Remote 端
在 Remote 端執行 gdbserver,執行 gdbserver 後面參數加上 <ip:port> 監聽的ip位址與port通訊埠以及要偵錯的執行檔路徑,這邊範例使用 port 20000,

1
gdbserver 192.168.0.2:20000 samplehello

gdbserver 要使用 attach 的方式的話,後面接上程式的 pid 即可,

1
gdbserver 192.168.0.2:20000 --attach <pid>

Local 端
在 Local 端執行 gdb,後面參數接上執行檔(debug 版本,no striped),執行 gdb 後使用 target remote <ip:port> 來連上遠端的 gdbserver,這邊範例是連上本地端的 port 20000,這樣 Remote 的 gdbserver 就收到連線請求,

1
2
gdb samplehello
(gdb) target remote 192.168.0.2:20000

一般 gdb 除錯時是使用 r 開始執行程式。不過遠端除錯時,遠端的 gdbserver 已經 run 了,所以 gdb 要用 c 來繼續執行,不能用 r。

以下為 gdb 常用的指令,
r:run 開始執行
c:continue 繼續執行
b main.cpp:14:設定中斷點
info b:印出目前設定的中斷點
bt:backtrace 印出程式呼叫的堆疊
q:quit 離開

以上就是 gdbserver 遠端除錯教學介紹,
如果你覺得我的文章寫得不錯、對你有幫助的話記得 Facebook 按讚支持一下!

相關主題
gdb 除錯教學
LLDB 除錯教學

gdb 除錯教學

本篇 ShengYu 介紹 gdb 除錯教學,全名為 GNU Debugger,是 GNU 軟體系統中的標準偵錯器 Debugger,在使用 Debugger 時可以單步執行、執行到中斷點、查看變數內容、印出呼叫堆疊等等功能,是程式設計師的常用工具,以下將會介紹編譯完 C/C++ 程式後怎麼使用 gdb 來替 C/C++ 程式偵錯。

以下 gdb 除錯教學的內容大概分為這幾部分,

  • gcc/g++ 編譯 C/C++ 程式
  • gdb 進行除錯

那我們開始吧!

gcc/g++ 編譯 C/C++ 程式

我的桌機環境為 Ubuntu 16.04,以下為一個簡單的 C/C++ 程式,使用 g++ main.cpp -g -o a.out 進行編譯,編譯成功後會產生 a.out 執行檔,-g 表示帶有除錯資訊,

main.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// g++ main.cpp -g -o a.out
#include <iostream>
#include <string>

int main() {
std::string s = "hello world";

int sum = 0;
for (int i = 0; i < 5; i++) {
sum += i;
}

std::cout << s << "\n";
std::cout << "sum=" << sum << "\n";
std::cout << "end\n";

return 0;
}

程式輸出如下,

1
2
3
hello world
sum=10
end

gdb 進行除錯

接著使用 gdb 指令對 a.out 進行除錯,執行 gdb ./a.out 指令進入 gdb 交互介面,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
$ gdb ./a.out 
GNU gdb (Ubuntu 7.11.1-0ubuntu1~16.5) 7.11.1
Copyright (C) 2016 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from a.out...done.
(gdb)

輸入 b main.cpp:14 插入中斷點在 main.cpp 的 14 行,

1
2
3
(gdb) b main.cpp:14
Breakpoint 1 at 0x400c09: file main.cpp, line 14.
(gdb)

輸入 info b 印出目前設定的中斷點,

1
2
3
4
(gdb) info b
Num Type Disp Enb Address What
1 breakpoint keep y 0x0000000000400c09 in main() at main.cpp:14
(gdb)

按下 r 開始執行,

1
2
3
4
5
6
7
(gdb) r
Starting program: /home/shengyu/a.out
hello world

Breakpoint 1, main () at main.cpp:14
14 std::cout << "sum=" << sum << "\n";
(gdb)

再次輸入 info b 印出目前設定的中斷點,可以看到中斷點被觸發幾次,

1
2
3
4
5
(gdb) info b
Num Type Disp Enb Address What
1 breakpoint keep y 0x0000000000400c09 in main() at main.cpp:14
breakpoint already hit 1 time
(gdb)

接著按 c 繼續執行直到程式結束,

1
2
3
4
5
6
(gdb) c
Continuing.
sum=10
end
[Inferior 1 (process 14925) exited normally]
(gdb)

以下為 gdb 常用的指令,
r:run 開始執行
c:continue 繼續執行
b main.cpp:14:設定中斷點
info b:印出目前設定的中斷點
bt:backtrace 印出程式呼叫的堆疊
q:quit 離開

以上就是 gdb 除錯教學介紹,
如果你覺得我的文章寫得不錯、對你有幫助的話記得 Facebook 按讚支持一下!

其他參考
C語言工具使用,GDB個人學習筆記 - iT 邦幫忙::一起幫忙解決難題,拯救 IT 人的一天
https://ithelp.ithome.com.tw/articles/10257294

相關主題
gdbserver 遠端除錯教學
LLDB 除錯教學

Ubuntu 使用 VS Code Debugger 除錯教學

本篇 ShengYu 介紹在 Ubuntu 使用 Visual Studio Code(VS Code) 設定 C/C++ 除錯的環境,

以下 Ubuntu 使用 VS Code 設定除錯環境的內容大概分為

  • VS Code 除錯環境設定
  • VS Code 偵錯前先編譯
  • VS Code 開啟 make 專案
  • VS Code 開啟 cmake 專案
  • VS Code 錯誤排除

那我們開始吧!

VS Code 除錯環境設定

我的 VS Code 版本為 1.68.0,Ubuntu 版本為 16.04,
在新專案下按下 F5 時如果沒有 .vscode/launch.json 設定檔的話,會跳出一些選項讓你選擇,如圖中的 C++: clang++

編譯時,新專案下沒有 .vscode/tasks.json 設定檔的話,也會跳出選項讓你選擇,這邊是示範選擇使用 clang++,用 g++ 也可以,

會在資料夾下產生 .vscode/launch.json 設定如下,如果沒有的話自己手動新增也可以,

.vscode/launch.json
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "clang - Build and debug active file",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/a.out",
"args": [],
"stopAtEntry": false,
"cwd": "${fileDirname}",
"environment": [],
"externalConsole": false,
"MIMode": "lldb",
"setupCommands": [
{
"description": "Enable pretty-printing for gdb",
"text": "-enable-pretty-printing",
"ignoreFailures": true
}
],
"miDebuggerPath": "/usr/bin/lldb-mi"
}
]
}

編譯 C/C++ 時記得加上 -g 選項,按 F5 執行 Start Debugging 後,就成功了!

VS Code 偵錯前先編譯

VS Code 按下 F5 要先編譯再啟動偵錯的話,要在 launch.json 加上 preLaunchTask,如下範例,

.vscode/launch.json
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "clang - Build and debug active file",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/a.out",
"args": [],
"stopAtEntry": false,
"cwd": "${fileDirname}",
"environment": [],
"externalConsole": false,
"MIMode": "lldb",
"setupCommands": [
{
"description": "Enable pretty-printing for gdb",
"text": "-enable-pretty-printing",
"ignoreFailures": true
}
],
"preLaunchTask": "C/C++: clang build active file",
"miDebuggerPath": "/usr/bin/lldb-mi"
}
]
}

launch.json 的 "preLaunchTask": "C/C++: clang build active file" 是對應到 tasks.json 的 label 名稱,

.vscode/tasks.json
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
{
"tasks": [
{
"type": "cppbuild",
"label": "C/C++: clang build active file",
"command": "/usr/bin/clang++",
"args": [
"-g",
"${file}",
"-o",
"${fileDirname}/a.out"
],
"options": {
"cwd": "${fileDirname}"
},
"problemMatcher": [
"$gcc"
],
"group": {
"kind": "build",
"isDefault": true
},
"detail": "Task generated by Debugger."
}
],
"version": "2.0.0"
}

這樣按 F5 啟動偵錯前會先編譯,成功編譯才會啟動偵錯。

詳細的 .vscode 設定可以參考 https://github.com/shengyu7697/vscode-debugging/tree/master/ubuntu-lldb

其他參考
launch.json 參數說明
Visual Studio Code (VSCode) 之 C/C++ 调试配置详解
[VSCode] Visual Studio Code 執行 C++ (2) - IntelliSense + Building + Debugging

VS Code 開啟 make 專案

make 專案編譯時會使用 Makefile 來執行裡面的腳本,所以 .vscode/tasks.json 不能在使用 cppbuild type 要換成 shell 來執行 make 這個指令,

然後 command 換成 cd ${workspaceFolder}; /usr/bin/make,如下所示,

.vscode/tasks.json
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
{
"tasks": [
{
"type": "shell",
"label": "C/C++: make build",
"command": "cd ${workspaceFolder}; /usr/bin/make",
"args": [],
"options": {
"cwd": "${fileDirname}"
},
"problemMatcher": [
"$gcc"
],
"group": {
"kind": "build",
"isDefault": true
},
"detail": "偵錯工具產生的工作。"
}
],
"version": "2.0.0"
}

這邊也可以參考 Stack Overflowgithub gist 兩篇的其他種做法。

VS Code 開啟 cmake 專案

cmake 專案在 generate 時,要使用 cmake -DCMAKE_BUILD_TYPE=Debug .. 給定編譯 Debug 版本,之後編譯出來的執行檔才有除錯的資訊,或者在 CMakeLists.txt 直接寫死是 Debug 版本,

CMakeLists.txt
1
set(CMAKE_BUILD_TYPE "Debug")

.vscode/tasks.json 這邊可以參考這篇的寫法,將 cmake generate 與 cmake build 分成兩個 task,再用 C/C++: cmake build 這個 task 將前兩者串起來,

.vscode/tasks.json
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
{
"tasks": [
{
"label": "C/C++: cmake build",
"dependsOrder": "sequence",
"dependsOn":["cmake generate", "cmake build"]
},
{
"type": "shell",
"label": "cmake generate",
"command": "cd ${workspaceFolder}/build; /usr/bin/env cmake ..",
"args": []
},
{
"type": "shell",
"label": "cmake build",
"command": "cd ${workspaceFolder}/build; /usr/bin/env cmake --build .",
"args": [],

"problemMatcher": [
"$gcc"
],
"group": {
"kind": "build",
"isDefault": true
},
"detail": "偵錯工具產生的工作。"
}
],
"options": {
"cwd": "${workspaceRoot}/build"
},
"version": "2.0.0"
}

VS Code 錯誤排除

如果在除錯的過程中逐步執行發現跳不到原始碼遇到 Could not load source ... 'SourceRequest' not supported 這樣的錯誤訊息的話,可能就是找不到原始碼的路徑,可能就是因為執行檔跟原始碼擺放路徑不同,解決方式就是在 launch.json 使用 sourceFileMap 將正確的路徑對應好,再次啟動就可以正確找到了~~

以上就是 Ubuntu 使用 VS Code Debugger 除錯介紹,
如果你覺得我的文章寫得不錯、對你有幫助的話記得 Facebook 按讚支持一下!

其他參考
Debug a C++ project in VS Code - Youtube

其它相關文章推薦
macOS 使用 VS Code Debugger 除錯教學
Visual Studio Code 常用快捷鍵
VS Code 新增 C++ 標頭檔路徑

Android 使用 gdb 搭配 Visual Studio Code 遠端除錯教學

本篇 ShengYu 介紹 Android 使用 gdb 與 gdbserver 以及搭配 Visual Studio Code(VS Code) 來遠端除錯,gdb 可以透過網路對遠端的程式進行除錯,需要遠端執行 gdbserver 以及搭配本地端 gdb 一起使用,而 gdbserver 是 server 的角色,而 gdb 是 client 的角色,一旦 gdb 連上遠端的 gdbserver 後,之後就使用 gdb 進行除錯,跟平常的 gdb 使用上沒有差異,我的桌機環境為 Ubuntu 16.04,

以下 Android 使用 gdb 搭配 Visual Studio Code 遠端除錯教學內容大概分為這幾部分,

  • adb forward 轉發通訊埠
  • Android 下 gdb 與 gdbserver 使用方法
  • VS Code 遠端偵錯設定
  • VS Code 錯誤排除

adb forward 轉發通訊埠

adb forward 將 PC 的 port 20001 對應到 Android Device 的 port 20002,

1
adb forward tcp:20001 tcp:20002

可以使用 adb forward --list 檢查目前的轉發列表。

Android 下 gdb 與 gdbserver 使用方法

將編譯好的執行檔推到 Android Device,假設這個執行檔名稱叫 samplehello,在編譯時要確保有 -g 選項以及 -O0 不使用最佳化,以便提供足夠的偵錯資訊,

gdb 與 gdbserver 不用自己編譯,直接拿 Android 預編譯好的執行檔即可,以 NDK r13b 為例的話,也可以使用最新的 NDK,要注意的是 NDK r24 就移除 gdb/gdbserver 改用 lldb 了,所以 NDK r24 之後的版本改用 lldb,
gdb 執行檔路徑如下,

1
2
3
android-ndk-r13b-windows-x86_64.zip -> android-ndk-r13b/prebuilt/windows-x86_64/bin/gdb.exe
android-ndk-r13b-linux-x86_64.zip -> android-ndk-r13b/prebuilt/linux-x86_64/bin/gdb
android-ndk-r13b-darwin-x86_64.zip -> android-ndk-r13b/prebuilt/darwin-x86_64/bin/gdb

gdbserver 執行檔路徑如下,gdbserver 是在 Android Device 端執行的程式,視你要除錯的執行檔類型選擇對應架構的 gdbserver,

1
2
3
4
5
6
android-ndk-r13b-windows-x86_64.zip -> android-ndk-r13b/prebuilt/android-arm/gdbserver/gdbserver
android-ndk-r13b-windows-x86_64.zip -> android-ndk-r13b/prebuilt/android-arm64/gdbserver/gdbserver
android-ndk-r13b-linux-x86_64.zip -> android-ndk-r13b/prebuilt/android-arm/gdbserver/gdbserver
android-ndk-r13b-linux-x86_64.zip -> android-ndk-r13b/prebuilt/android-arm64/gdbserver/gdbserver
android-ndk-r13b-darwin-x86_64.zip -> android-ndk-r13b/prebuilt/android-arm/gdbserver/gdbserver
android-ndk-r13b-darwin-x86_64.zip -> android-ndk-r13b/prebuilt/android-arm64/gdbserver/gdbserver

或者使用 Android BSP / AOSP source code 裡附帶的也可以,預編譯好的 gdb 與 gdbserver 就在 prebuilts 目錄下。

Android Device 端
在 Android Device 端執行 gdbserver 或 gdbserver64,假使要除錯的執行檔 (samplehello) 是 64bit 架構的就使用 gdbserver64,反之使用 gdbserver,使用錯誤的話到時 gdb 端會顯示錯誤訊息,執行 gdbserver 後面參數加上 <ip:port> 監聽的ip位址與port通訊埠以及要偵錯的執行檔路徑,這邊範例使用 port 20002,

1
2
3
gdbserver64 :20002 /vendor/bin/samplehello
# or
gdbserver64 127.0.0.1:20002 /vendor/bin/samplehello

gdbserver 要使用 attach 的方式的話,後面接上程式的 pid 即可,

1
gdbserver64 :20002 --attach <pid>

PC 端
在 PC 端執行 gdb,後面參數接上執行檔(debug 版本,no striped),這裡使用 codebase 預編譯好的 gdb,執行 gdb 後使用 target remote <ip:port> 來連上遠端的 gdbserver,這邊範例是連上本地端的 port 20001,因為稍早的 adb forward 設定會將 PC 本地端的 port 20001 轉發到 Android Device 遠端的 port 20002,使得 Android Device 上的 gdbserver 收到連線請求,

1
2
3
4
./prebuilts/gdb/linux-x86/bin/gdb ./out/target/product/<product_name>/symbols/vendor/bin/samplehello
(gdb) target remote :20001
# or
(gdb) target remote 127.0.0.1:20001

一般 gdb 除錯時是使用 r 開始執行程式。不過遠端除錯時,遠端的 gdbserver 已經 run 了,所以 gdb 要用 c 來繼續執行,不能用 r。

以下為 gdb 常用的指令,
r:run 開始執行
c:continue 繼續執行
b samplehello.cpp:14:設定中斷點
info b:印出目前設定的中斷點
bt:backtrace 印出程式呼叫的堆疊
q:quit 離開

確定基本的 gdbserver 與 gdb 都可以正常地遠端偵錯後,我們就來開始進行 VS Code 遠端偵錯的設定吧!

VS Code 遠端偵錯設定

VS Code 的 .vscode/launch.json 設定檔資訊如下,其中重點是 miDebuggerServerAddress 要設定對,例如本範例的 PC 本地端 port 20001 (轉發到 Android Device 遠端的 port 20002),miDebuggerPath 是 gdb 執行檔的路徑,最後是 program 要除錯的執行檔路徑,

.vscode/launch.json
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "Remote GDB",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/out/target/product/<product_name>/symbols/vendor/bin/samplehello",
"args": [],
"stopAtEntry": false,
"cwd": "${workspaceFolder}",
"environment": [],
"externalConsole": false,
"MIMode": "gdb",
"setupCommands": [
{
"description": "Enable pretty-printing for gdb",
"text": "-enable-pretty-printing",
"ignoreFailures": true
}
],
"miDebuggerServerAddress": "localhost:20001",
"miDebuggerPath": "${workspaceFolder}/prebuilts/gdb/linux-x86/bin/gdb"
//"miDebuggerPath": "/opt/android-ndk-r13b/prebuilt/linux-x86_64/bin/gdb"
}
]
}

VS Code 錯誤排除

如果在除錯的過程中逐步執行發現跳不到原始碼遇到 Could not load source ... 'SourceRequest' not supported 這樣的錯誤訊息的話,可能就是找不到原始碼的路徑,可能就是因為執行檔跟原始碼擺放路徑不同,解決方式就是在 launch.json 使用 sourceFileMap 將正確的路徑對應好,再次啟動就可以正確找到了~~

類似的狀況與解法可以在medium這篇vscode-cpptools issues這兩篇中發現。

其他參考
Android Debugging with Visual Studio Code - General and Gameplay Programming - Tutorials - GameDev.net
https://www.gamedev.net/tutorials/programming/general-and-gameplay-programming/android-debugging-with-visual-studio-code-r4820/
GDBServer on Android
https://appleapplecat.pixnet.net/blog/post/32464205
Using Debuggers | Android Open Source Project 官方最新文件
https://source.android.google.cn/devices/tech/debug/gdb
Debugging with GDB | Android Open Source 很舊的文件
https://wladimir-tm4pda.github.io/porting/debugging_gdb.html
(在 Android 6 及更低版本,gdbclient 的 shell 腳本,Android 6 以上是 gdbclient.py 的 python 腳本)
使用GDB在VS Code調試Android C/C++代碼(無需Android源碼)_陳六生的博客-CSDN博客
https://blog.csdn.net/u011057800/article/details/108094858
(launch.json 使用 ${env:ANDROID_NDK} 取得環境變數的設定值)

相關主題
Android adb forward 通訊埠轉發用法教學
macOS 使用 VS Code Debugger 除錯

Android adb forward 通訊埠轉發用法教學

本篇 ShengYu 介紹 Android 的 adb forward 通訊埠轉發的功能,adb forward 的功能是轉發 PC 電腦上某個埠號 (port) 資料到 Android 裝置的某個埠號 (port),例如:下列 adb forward 指令就是將 PC 端的 port 10000 收到的資料,轉發給到 Android Device 的 port 20000,

1
adb forward tcp:10000 tcp:20000

Android 5.0 及以上才支援使用 adb reverse 指令,且 adb 要 1.0.32 之後的版本才支援。

通常在 Android Device 會啟動一個 server 程式,而 PC 端的 client 程式想要連到 Android Device 的 server,除了使用 ip 的方式連線以外,沒有 ip 的話,還可以利用 USB 連線的方式,也就是透過 adb forward 轉發 port,如此一來 PC 端的 client 程式就可以連上 Android Device 的 server 程式,

adb forward 執行完後可以使用 adb forward --list 查看轉發列表,或者用 adb forward --remove-all 移除全部,

1
2
$ adb forward --list
XX00X0000000 tcp:10000 tcp:20000

如果要移除轉發的話,就這樣下,

1
adb forward --remove tcp:10000

如果要寫一個 PC Java client 與 Android Java server 通訊的話可以參考這篇後半部的範例

以上就是 Android adb forward 通訊埠轉發用法教學介紹,
如果你覺得我的文章寫得不錯、對你有幫助的話記得 Facebook 按讚支持一下!

其他參考
adb forward的細節(1):原理概述_愛博客大伯的博客-CSDN博客_adb forward
https://blog.csdn.net/u013553529/article/details/80036227
Android Debug Bridge (ADB) | Android Developers
https://developer.android.com/studio/command-line/adb.html#forwardports

相關主題
Android adb reverse 通訊埠轉發用法教學
Android adb 基本用法教學
Android adb 同步時間/設定時間
Android adb shell input 事件用法
Anddroid VS Code 遠端除錯教學

macOS 使用 VS Code Debugger 除錯教學

本篇 ShengYu 介紹在 macOS 使用 Visual Studio Code(VS Code) 設定 C/C++ 除錯的環境,

以下 macOS 使用 VS Code 設定除錯環境的內容大概分為

  • VS Code 除錯環境設定
  • VS Code 安裝 CodeLLDB extension
  • VS Code 偵錯前先編譯
  • VS Code 開啟 make 專案
  • VS Code 開啟 cmake 專案
  • VS Code 錯誤排除

那我們開始吧!

VS Code 除錯環境設定

我的 VS Code 版本為 1.67.2,macOS 版本為 10.13.4,
在新專案下按下 F5 時如果沒有 .vscode/launch.json 設定檔的話,會跳出一些選項讓你選擇,如圖中的 C++ (GDB/LLDB)

新專案下沒有 .vscode/tasks.json 設定檔的話,也會跳出選項讓你選擇,由於 macOS 早就已經棄用 gcc,所以這邊是選擇使用 clang,

會在資料夾下產生 .vscode/launch.json 設定如下,如果沒有的話自己手動新增也可以,

.vscode/launch.json
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "(lldb) Launch",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/a.out",
"args": [],
"stopAtEntry": false,
"cwd": "${fileDirname}",
"environment": [],
"externalConsole": false,
"MIMode": "lldb",
}
]
}

編譯 C/C++ 時記得加上 -g 選項,按 F5 執行 Start Debugging 後,
出現 Unable to start debugging. LLDB exited unexpectedly with exit code 137 (0x89). 如下圖所示,

看到這篇文章分享將 .vscode/launch.json 的 type 從原本的 cppdbg 改成 lldb 就可以使用了,type 改成 lldb 後像這樣,

.vscode/launch.json
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "(lldb) Launch",
"type": "lldb",
"request": "launch",
"program": "${workspaceFolder}/a.out",
"args": [],
"stopAtEntry": false,
"cwd": "${fileDirname}",
"environment": [],
"externalConsole": false,
"MIMode": "lldb",
}
]
}

.vscode/launch.json 的 type 改成 lldb 後,再按 F5 執行 Start Debugging 後,
出現 Configured debug type 'lldb' is not supported. 如下圖所示,

看到這篇 troyibm 這位網友他也遇到同樣的問題,結果是安裝了 CodeLLDB 擴充套件就可以使用了!那我們來安裝 CodeLLDB 擴充套件吧。

VS Code 安裝 CodeLLDB extension

接下來就安裝CodeLLDB擴充套件,
網頁有寫支援的平台,

  • Linux with glibc 2.18+ for x86_64, aarch64 or armhf,
  • MacOS X 10.10+ for x86_64 and 11.0+ for arm64,
  • Windows 10 for x86_64.

看起來三大平台都有支援。

接著再次 F5 執行 Start Debugging 終於成功了!

經過這次安裝 CodeLLDB extension 後,之後在新專案要 按 F5 時會有 LLDB 新的選項,可以直接選擇 LLDB,

選擇 LLDB 後產生的 launch.json 如下,然後記得修改 program 裡的名稱,

.vscode/launch.json
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"type": "lldb",
"request": "launch",
"name": "Debug",
"program": "${workspaceFolder}/<your program>",
"args": [],
"cwd": "${workspaceFolder}"
}
]
}

VS Code 偵錯前先編譯

VS Code 按下 F5 要先編譯再啟動偵錯的話,要在 launch.json 加上 preLaunchTask,如下範例,

.vscode/launch.json
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"type": "lldb",
"request": "launch",
"name": "Debug",
"program": "${workspaceFolder}/a.out",
"args": [],
"cwd": "${workspaceFolder}",
"preLaunchTask": "C/C++: clang++ build"
}
]
}

launch.json 的 "preLaunchTask": "C/C++: clang++ build" 是對應到 tasks.json 的 label 名稱,

.vscode/tasks.json
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
{
"tasks": [
{
"type": "cppbuild",
"label": "C/C++: clang++ build",
"command": "/usr/bin/clang++",
"args": [
"-fdiagnostics-color=always",
"-g",
"${file}",
"-o",
"${fileDirname}/a.out"
],
"options": {
"cwd": "${fileDirname}"
},
"problemMatcher": [
"$gcc"
],
"group": {
"kind": "build",
"isDefault": true
},
"detail": "偵錯工具產生的工作。"
}
],
"version": "2.0.0"
}

這樣按 F5 啟動偵錯前會先編譯,成功編譯才會啟動偵錯。

詳細的 .vscode 設定可以參考 https://github.com/shengyu7697/vscode-debugging/tree/master/mac-lldb

其他參考
launch.json 參數說明
Visual Studio Code (VSCode) 之 C/C++ 调试配置详解
[VSCode] Visual Studio Code 執行 C++ (2) - IntelliSense + Building + Debugging

make 專案

make 專案編譯時會使用 Makefile 來執行裡面的腳本,所以 .vscode/tasks.json 不能在使用 cppbuild type 要換成 shell 來執行 make 這個指令,

然後 command 換成 cd ${workspaceFolder}; /usr/bin/make,如下所示,

.vscode/tasks.json
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
{
"tasks": [
{
"type": "shell",
"label": "C/C++: make build",
"command": "cd ${workspaceFolder}; /usr/bin/make",
"args": [],
"options": {
"cwd": "${fileDirname}"
},
"problemMatcher": [
"$gcc"
],
"group": {
"kind": "build",
"isDefault": true
},
"detail": "偵錯工具產生的工作。"
}
],
"version": "2.0.0"
}

這邊也可以參考 Stack Overflowgithub gist 兩篇的其他種做法。

cmake 專案

cmake 專案在 generate 時,要使用 cmake -DCMAKE_BUILD_TYPE=Debug .. 給定編譯 Debug 版本,之後編譯出來的執行檔才有除錯的資訊,或者在 CMakeLists.txt 直接寫死是 Debug 版本,

CMakeLists.txt
1
set(CMAKE_BUILD_TYPE "Debug")

.vscode/tasks.json 這邊可以參考這篇的寫法,將 cmake generate 與 cmake build 分成兩個 task,再用 C/C++: cmake build 這個 task 將前兩者串起來,

.vscode/tasks.json
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
{
"tasks": [
{
"label": "C/C++: cmake build",
"dependsOrder": "sequence",
"dependsOn":["cmake generate", "cmake build"]
},
{
"type": "shell",
"label": "cmake generate",
"command": "cd ${workspaceFolder}/build; /usr/bin/env cmake ..",
"args": []
},
{
"type": "shell",
"label": "cmake build",
"command": "cd ${workspaceFolder}/build; /usr/bin/env cmake --build .",
"args": [],

"problemMatcher": [
"$gcc"
],
"group": {
"kind": "build",
"isDefault": true
},
"detail": "偵錯工具產生的工作。"
}
],
"options": {
"cwd": "${workspaceRoot}/build"
},
"version": "2.0.0"
}

VS Code 錯誤排除

如果在除錯的過程中逐步執行發現跳不到原始碼遇到 Could not load source ... 'SourceRequest' not supported 這樣的錯誤訊息的話,可能就是找不到原始碼的路徑,可能就是因為執行檔跟原始碼擺放路徑不同,解決方式就是在 launch.json 使用 sourceFileMap 將正確的路徑對應好,再次啟動就可以正確找到了~~

以上就是 macOS 使用 VS Code Debugger 除錯介紹,
如果你覺得我的文章寫得不錯、對你有幫助的話記得 Facebook 按讚支持一下!

其他參考
Debug a C++ project in VS Code - Youtube

其它相關文章推薦
Ubuntu 使用 VS Code Debugger 除錯教學
Visual Studio Code 常用快捷鍵
VS Code 新增 C++ 標頭檔路徑