[譯]用 LLDB 調試 Swift 代碼

2021-02-15 Cocoa開發者社區

原文地址:Debugging Swift code with LLDB

原文作者:Ahmed Sulaiman

譯文出自:掘金翻譯計劃

本文永久連結:github.com/xitu/gold-m…

譯者:VernonVan

校對者:ZhiyuanSun、Danny1451

作為工程師,我們花了差不多 70% 的時間在調試上,剩下的 20% 用來思考架構以及和組員溝通,僅僅只有 10% 的時間是真的在寫代碼的。

調試就像是在犯罪電影中做偵探一樣,同時你也是兇手。

— Filipe Fortes 來自 Twitter

所以讓我們在這70%的時間儘可能愉悅是相當重要的。LLDB 就是來打救我們的。奇妙的 Xcode Debugger UI 展示了所有你可用的信息,而不用敲入任何一個 LLDB 命令。然而,控制臺在我們的工作中同樣也是很重要的一部分。現在讓我們來分析一些最有用的 LLDB 技巧。我自己每天都在用它們進行調試。

從哪裡開始呢?

LLDB 是一個龐大的工具,內置了很多有用的命令。我不會全部講解,而是帶你瀏覽最有用的命令。這是我們的計劃:

獲取變量值:expression, e, print, po, p

獲取整個應用程式的狀態以及特定語言的命令:bugreport, frame, language

控制應用的執行流程:process, breakpoint, thread, watchpoint

榮譽獎:command, platform, gui

我還準備好了有用的 LLDB 命令說明和實例的表格,有需要的可以把它貼在 Mac 上面記住這些命令 

通過這條連結下載全尺寸的版本 —  www.dropbox.com/s/9sv67e7f2…

1. 獲取變量值和狀態

命令:expression, e, print, po, p

調試器的一個基礎功能就是獲取和修改變量的值。這就是 expression 或者 e 被創造的原因(當然他們還有更高級的功能)。您可以簡單的在運行時執行任何表達式或命令。

假設你現在正在調試方法 valueOfLifeWithoutSumOf() :對兩個數求和,再用42去減得到結果。

繼續假設你一直得到錯誤的結果並且你並不知道是什麼原因。所以你可以做以下的事來找到問題:

或者。。。使用 LLDB 表達式在運行時修改值才是更好的方法,同時可以找出問題是在哪裡出現的。首先,在你感興趣的地方設置一個斷點,然後運行你的應用。

為了用 LLDB 格式列印指定的變量你應該調用:

(lldb) e <variable>

使用相同的命令來執行一些表達式:

(lldb) e <expression>

(lldb) e sum 

(Int) $R0 = 6 // 下面你也可以用 $R0 來引用這個變量(在本次調試過程中)

(lldb) e sum = 4 // 修改變量 sum 的值

(lldb) e sum 

(Int) $R2 = 4 // 直到本次調試結束變量 sum 都會是 "4" 

expression 命令也有一些標誌。在 expression 後面用雙破折號 -- 將標誌和實際的表達式分隔開,就像這樣:

(lldb) expression <some flags> -- <variable>

expression 命令差不多有30種不同的標誌。我鼓勵你多去探索它們。在終端中鍵入以下命令可以看到完整的文檔:

> lldb

> (lldb) help # 獲取所有變量的命令

> (lldb) help expression # 獲取所有表達式的子命令

我會在下列 expression 的標誌上多停留一會兒:

-D <count> (--depth <count>)  — 設置在轉儲聚合類型時的最大遞歸深度(默認為無窮大)。

-O (--object-description)  — 如果可能的話,使用指定語言的描述API來顯示。

-T (--show-types)  — 在轉儲值的時候顯示變量類型。

-f <format> (--format <format>) — 指定一種用於顯示的格式。

-i <boolean> (--ignore-breakpoints <boolean>) — 在運行表達式時忽略斷點。

假設我們有一個叫 logger 的對象,這個對象有一些字符串和結構體類型的屬性。比如說,你可能只是想知道第一層的屬性,那只需要用 -D 標誌以及恰當的層級深度值,就像這樣:

(lldb) e -D 1 -- logger

(LLDB_Debugger_Exploration.Logger) $R5 = 0x0000608000087e90 {

  currentClassName = "ViewController"

  debuggerStruct ={...}

}

默認情況下,LLDB 會無限地遍歷該對象並且給你展示每個嵌套的對象的完整描述:

(lldb) e -- logger

(LLDB_Debugger_Exploration.Logger) $R6 = 0x0000608000087e90 {

  currentClassName = "ViewController"

  debuggerStruct = (methodName = "name", lineNumber = 2, commandCounter = 23)

}

你也可以用 e -O -- 獲取對象的描述或者更簡單地用別名 po,就像下面的示例一樣:

(lldb) po logger

<Logger: 0x608000087e90>

並不是很有描述性,不是嗎?為了獲取更加可閱讀的描述,你自定義的類必須遵循 CustomStringConvertible 協議,同時實現 var description: String { return ...} 屬性。接下來只需要用 po 就能返回可讀的描述。


在本節的開始,我也提到了 print 命令。基本上 print <expression/variable> 就等同於 expression -- <expression/variable>。但是 print 命令不能帶任何標誌或者額外的參數。

2. 獲取整個 APP 的狀態和指定語言的命令

bugreport, frame, language

你是否經常複製粘貼崩潰日誌到任務管理器中方便稍後能考慮這個問題嗎?LLDB 提供了一個很好用的命令叫 bugreport,這個命令能生成當前應用狀態的完整報告。在你偶然觸發某些問題但是想在稍後再解決它時這個命令就會很有幫助了。為了能恢復應用的狀態,你可以使用 bugreport 生成報告。

(lldb) bugreport unwind --outfile <path to output file>

最終的報告看起來就像下面截圖中的例子一樣:

bugreport 命令輸出的示例。

假設你想要獲取當前線程的當前棧幀的概述,frame 命令可以幫你完成:

使用下面的代碼片段來快速獲取當前地址以及當前的環境條件:

(lldb) frame info

frame #0: 0x000000010bbe4b4d LLDB-Debugger-Exploration`ViewController.valueOfLifeWithoutSumOf(a=2, b=2, self=0x00007fa0c1406900) -> Int at ViewController.swift:96

這些信息在本文後面將要說到的斷點管理中非常有用。

LLDB 有幾個指定語言的命令,包括C++,Objective-C,Swift 和 RenderScript。在這篇文章中,我們重點關注 Swift。這是兩個命令:demangle 和 refcount。

demangle 正如其名字而言,就是用來重組 Swift 類型名的(因為 Swift 在編譯的時候會生成類型名來避免命名空間的問題)。如果你想了解多一點的話,我建議你看 WWDC14 的這個分享會 —  「Advanced Swift Debugging in LLDB」。

refcount 同樣也是一個相當直觀的命令,能獲得指定對象的引用數量。一起來看一下對象輸出的示例,我們用了上一節講到的對象 — logger:

(lldb) language swift refcount logger

refcount data: (strong = 4, weak = 0)

當然了,在你調試某些內存洩露問題時,這個命令就會很有幫助。

3. 控制應用的執行流程

process, breakpoint, thread

這節是我最喜歡的一節,因為在 LLDB 使用這幾個命令(尤其是 breakpoint 命令),你可以在調試的時候使很多常規任務變得自動化,這樣就能大大加快你的調試工作。

通過 process 基本上你就可以控制調試的過程了,還能連結到特定的 target 或者停止調試器。 但是因為 Xcode 已經自動地幫我們做好了這個工作了(Xcode 在任何時候運行一個 target 時都會連接 LLDB)。我不會在這兒講太多,你可以在這篇 Apple 的指南中閱讀一下如何用終端連接到一個 target — 「Using LLDB as a Standalone Debugger」。

使用 process status 的話,你可以知道當前調試器停住的地址:

(lldb) process status

Process 27408 stopped

* thread #1, queue = 'com.apple.main-thread', stop reason = step over

frame #0: 0x000000010bbe4889 LLDB-Debugger-Exploration`ViewController.viewDidLoad(self=0x00007fa0c1406900) -> () at ViewController.swift:69

66

67           let a = 2, b = 2

68           let result = valueOfLifeWithoutSumOf(a, and: b)

-> 69           print(result)

70

71

72

想要繼續 target 的執行過程直到遇到下次斷點的話,運行這個命令:

(lldb) process continue

(lldb) c // 或者只鍵入 "c",這跟上一條命令是一樣的

這個命令等同於 Xcode 調試器工具欄上的」continue「按鈕:

breakpoint 命令允許你用任何可能的方式操作斷點。我們跳過最顯而易見的命令:breakpoint enable, breakpoint disable和 breakpoint delete。

首先,查看你所有斷點的話可以用如下示例中的 list 子命令:

(lldb) breakpoint list

Current breakpoints:

1: file = '/Users/Ahmed/Desktop/Recent/LLDB-Debugger-Exploration/LLDB-Debugger-Exploration/ViewController.swift', line = 95, exact_match = 0, locations = 1, resolved = 1, hit count = 1

1.1: where = LLDB-Debugger-Exploration`LLDB_Debugger_Exploration.ViewController.valueOfLifeWithoutSumOf (Swift.Int, and : Swift.Int) -> Swift.Int + 27 at ViewController.swift:95, address = 0x0000000107f3eb3b, resolved, hit count = 1

2: file = '/Users/Ahmed/Desktop/Recent/LLDB-Debugger-Exploration/LLDB-Debugger-Exploration/ViewController.swift', line = 60, exact_match = 0, locations = 1, resolved = 1, hit count = 1

2.1: where = LLDB-Debugger-Exploration`LLDB_Debugger_Exploration.ViewController.viewDidLoad () -> () + 521 at ViewController.swift:60, address = 0x0000000107f3e609, resolved, hit count = 1

列表中的第一個數字是是斷點的 ID,你可以通過這個 ID 引用到指定的斷點。現在讓我們在控制臺中設置一些新的斷點:

(lldb) breakpoint set -f ViewController.swift -l 96

Breakpoint 3: where = LLDB-Debugger-Exploration`LLDB_Debugger_Exploration.ViewController.valueOfLifeWithoutSumOf (Swift.Int, and : Swift.Int) -> Swift.Int + 45 at ViewController.swift:96, address = 0x0000000107f3eb4d

這個例子中的 -f 是你想要放置斷點處的文件名,-l 是新斷點的行數。還有一種更簡潔的方式設置同樣的斷點,就是用快捷方式 b:

(lldb) b ViewController.swift:96

同樣地,你也可以用指定的正則(比如函數名)來設置斷點,使用下面的命令:

(lldb) breakpoint set --func-regex valueOfLifeWithoutSumOf

(lldb) b -r valueOfLifeWithoutSumOf // 上一條命令的簡化版本

有些時候設置斷點只命中一次也是有用的,然後指示這個斷點立即刪除自己,當然啦,有一個命令來處理這件事:

(lldb) breakpoint set --one-shot -f ViewController.swift -l 90

(lldb) br s -o -f ViewController.swift -l 91 // 上一條命令的簡化版本

現在我們來到了最有趣的部分 — 自動化斷點。你知道你可以設置一個特定的動作使它在斷點停住的時候執行嗎?是的,你可以!你是否會在代碼中用 print() 來在調試的時候得到你感興趣的值?請不要再這樣做了,這裡有一種更好的方法。

通過 breakpoint 命令,你可以設置好命令,使其在斷點命中時可以正確執行。你甚至可以設置」不可見「的斷點,這種斷點並不會打斷運行過程。從技術上講,這些「不可見的」斷點其實是會中斷執行的,但如果在命令鏈的末尾添上「continue」命令的話,你就不會注意到它。

(lldb) b ViewController.swift:96 // Let's add a breakpoint first

Breakpoint 2: where = LLDB-Debugger-Exploration`LLDB_Debugger_Exploration.ViewController.valueOfLifeWithoutSumOf (Swift.Int, and : Swift.Int) -> Swift.Int + 45 at ViewController.swift:96, address = 0x000000010c555b4d

(lldb) breakpoint command add 2 // 準備某些命令

Enter your debugger command(s).  Type 'DONE' to end.

> p sum // 列印變量 "sum" 的值

> p a + b // 運行 a + b

> DONE

為了確保你添加的命令是正確的,可以使用 breakpoint command list <breakpoint id> 子命令:

(lldb) breakpoint command list 2

Breakpoint 2:

Breakpoint commands:

p sum

p a + b

當下次斷點命中時我們就會在控制臺看到下面的輸出:

Process 36612 resuming

p sum

(Int) $R0 = 6

p a + b

(Int) $R1 = 4

太棒了!這正是我們想要的。你可以通過在命令鏈的末尾添加 continue 命令讓執行過程更加順暢,這樣你就不會停在這個斷點。

(lldb) breakpoint command add 2 // 準備某些命令

Enter your debugger command(s).  Type 'DONE' to end.

> p sum // 列印變量 "sum" 的值

> p a + b // 運行 a + b

> continue // 第一次命中斷點後直接恢復

> DONE

結果會是這樣:

p sum

(Int) $R0 = 6

p a + b

(Int) $R1 = 4

continue

Process 36863 resuming

Command #3 'continue' continued the target.

通過 thread 命令和它的子命令,你可以完全操控執行流程:step-over, step-in, step-out 和 continue。這些命令等同於 Xcode 調試器工具欄上的流程控制按鈕。

LLDB 同樣也對這些特殊的命令預先定義好了快捷方式:

(lldb) thread step-over

(lldb) next // 和 "thread step-over" 命令效果一樣

(lldb) n // 和 "next" 命令效果一樣

(lldb) thread step-in

(lldb) step // 和 "thread step-in" 命令效果一樣

(lldb) s // 和 "step" 命令效果一樣

為了獲取當前線程的更多信息,我們只需要調用 info 子命令:

(lldb) thread info 

thread #1: tid = 0x17de17, 0x0000000109429a90 LLDB-Debugger-Exploration`ViewController.sumOf(a=2, b=2, self=0x00007fe775507390) -> Int at ViewController.swift:90, queue = 'com.apple.main-thread', stop reason = step in

想要看到當前所有的活動線程的話使用 list 子命令:

(lldb) thread list

Process 50693 stopped

* thread #1: tid = 0x17de17, 0x0000000109429a90 LLDB-Debugger-Exploration`ViewController.sumOf(a=2, b=2, self=0x00007fe775507390) -> Int at ViewController.swift:90, queue = 'com.apple.main-thread', stop reason = step in

  thread #2: tid = 0x17df4a, 0x000000010daa4dc6  libsystem_kernel.dylib`kevent_qos + 10, queue = 'com.apple.libdispatch-manager'

  

  thread #3: tid = 0x17df4b, 0x000000010daa444e libsystem_kernel.dylib`__workq_kernreturn + 10

  thread #5: tid = 0x17df4e, 0x000000010da9c34a libsystem_kernel.dylib`mach_msg_trap + 10, name = 'com.apple.uikit.eventfetch-thread'

榮譽獎

command, platform, gui

在 LLDB 中你可以找到一個命令管理其他的命令,聽起來很奇怪,但實際上它是非常有用的小工具。首先,它允許你從文件中執行一些 LLDB 命令,這樣你就可以創建一個儲存著一些實用命令的文件,然後就能立刻允許這些命令,就像是單個命令那樣。這是所說的文件的簡單例子:

thread info // 顯示當前線程的信息

br list // 顯示所有的斷點

下面是實際命令的樣子:

(lldb) command source /Users/Ahmed/Desktop/lldb-test-script

Executing commands in '/Users/Ahmed/Desktop/lldb-test-script'.

thread info

thread #1: tid = 0x17de17, 0x0000000109429a90 LLDB-Debugger-Exploration`ViewController.sumOf(a=2, b=2, self=0x00007fe775507390) -> Int at ViewController.swift:90, queue = 'com.apple.main-thread', stop reason = step in

br list

Current breakpoints:

1: file = '/Users/Ahmed/Desktop/Recent/LLDB-Debugger-Exploration/LLDB-Debugger-Exploration/ViewController.swift', line = 60, exact_match = 0, locations = 1, resolved = 1, hit count = 0

1.1: where = LLDB-Debugger-Exploration`LLDB_Debugger_Exploration.ViewController.viewDidLoad () -> () + 521 at ViewController.swift:60, address = 0x0000000109429609, resolved, hit count = 0

遺憾的是還有一個缺點,你不能傳遞任何參數給這個源文件(除非你在腳本文件本身中創建一個有效的變量)。

如果你需要更高級的功能,你也可以使用 script 子命令,這個命令允許你用自定義的 Python 腳本 管理(add, delete, import 和 list),通過 script 命令能實現真正的自動化。請閱讀這個優秀的教程 Python scripting for LLDB。為了演示的目的,讓我們創建一個腳本文件 script.py,然後寫一個簡單的命令 print_hello(),這個命令會在控制臺中列印出「Hello Debugger!「:

import lldb

def print_hello(debugger, command, result, internal_dict):

print "Hello Debugger!"

    

def __lldb_init_module(debugger, internal_dict):

debugger.HandleCommand('command script add -f script.print_hello print_hello') // 控制腳本的初始化同時從這個模塊中添加命令

print 'The "print_hello" python command has been installed and is ready for use.' // 列印確認一切正常 

接下來我們需要導入一個 Python 模塊,就能開始正常地使用我們的腳本命令了:

(lldb) command import ~/Desktop/script.py

The "print_hello" python command has been installed and is ready for use.

(lldb) print_hello

Hello Debugger!

你可以使用 status 子命令來快速檢查當前的環境信息,status 會告訴你:SDK 路徑、處理器的架構、作業系統版本甚至是該 SDK 可支持的設備的列表。

(lldb) platform status

Platform: ios-simulator

Triple: x86_64-apple-macosx

OS Version: 10.12.5 (16F73)

Kernel: Darwin Kernel Version 16.6.0: Fri Apr 14 16:21:16 PDT 2017; root:xnu-3789.60.24~6/RELEASE_X86_64

Hostname: 127.0.0.1

WorkingDir: /

SDK Path: "/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk"

Available devices:

614F8701-3D93-4B43-AE86-46A42FEB905A: iPhone 4s

CD516CF7-2AE7-4127-92DF-F536FE56BA22: iPhone 5

0D76F30F-2332-4E0C-9F00-B86F009D59A3: iPhone 5s

3084003F-7626-462A-825B-193E6E5B9AA7: iPhone 6

...

你不能在 Xcode 中使用 LLDB GUI 模式,但你總是可以從終端使用(LLDB GUI 模式)。

(lldb) gui

// 如果你試著在 Xcode 中執行這個 gui 命令的話,你將會看到這個錯誤:the gui command requires an interactive terminal。

這就是 LLDB GUI 模式看起來的樣子。

結論:

在這篇文章中,我只是淺析了 LLDB 的皮毛知識而已,即使 LLDB 已經有好些年頭了,但是仍然有許多人並沒有完全發揮出它的潛能。我只是對基本的方法做了一個概述,以及談了 LLDB 如何自動化調試步驟。我希望這會是有幫助的。

還有很多 LLDB 的方法並沒有寫到,然後還有一些視圖調試技術我沒有提及。如果你對這些話題感興趣的話,請在下面留下你的評論,我會更加樂於寫這些話題。

我強烈建議你打開終端,啟動 LLDB,只需要敲入 help,就會向你展示完整的文檔。你可以花費數小時去閱讀,但是我保證這將是一個合理的時間投資。因為了解你的工具是工程師真正產出的唯一途徑。

相關焦點

  • Android動態調試-不用IDA Pro
    為什麼不用gdb,因為lldb的出現,取代gdb只是遲早的事情,可以說gdb是Depracated。在 Android逆向之ARM64靜態分析對app的中的so進行了靜態分析,這篇文章介紹兩種動態調試的方式,一種是radare2,另一種是lldb。
  • Netflix 是如何實現 Android與iOS 共用一套代碼?
    在我們的 Android 與 iOS 應用當中,近 50% 的生產代碼與底層平臺保持解耦。 我們能夠靈活探索不同平臺(Android Jetpack Compose、Swift UI 等)上提供的最新技術,再無任何後顧之憂。
  • Swift 5.3 又更新了什麼新奇爽快的語法?
    先來幾個官方的例子:上面的代碼中 2 的情況是經常出現的,尾閉包的含義就不夠明確,以前最佳的方式應該為 3,但是兩個閉包被套在一個小括號裡,使得括號多重嵌套,可讀性下降。為了解決這個問題,蘋果使用了第 4 中方法--多重尾閉包。可以從代碼看出可讀性得到了很大的提升。
  • 人生苦短,我用 Visual Studio Code
    File -> open File -> 選擇自己新建的文件目錄我們新建一個main.c文件,寫上如下代碼:#include<stdio.h>intmain(){printf("
  • 蘋果將從12月1日起在 Apple Stor 推出「一小時代碼」活動
    站長之家(ChinaZ.com) 11月27日 消息:蘋果近日宣布,其年度的[一小時代碼]活動將在 12 月 1 日到 12 月 14 日在全球的apple store開展,從今天開始蘋果用戶可以申請註冊參與活動,活動適用於全年齡段,並且將為 6 至 12 歲的孩子提供專門的編程課程
  • 「Web前端開發進階篇」Chrome瀏覽器的調試使用
    作者Web前端開發進階篇自Google發布Chrome瀏覽器以來,其隨著Chrome瀏覽的優化及其附帶的Chrome開發者工具和額外的擴展程序,受到了廣大開發者的喜愛,越來越多的前端開發人員喜歡在Chrome裡開發調試代碼,對開發人員非常友好,許多的優秀插件可以幫助開發人員更高效完成開發工作,另外可以登錄,不管到哪裡,只要一登錄就可以實現同步,極為方便
  • 谷歌為何要養蘋果的親兒子Swift?原來意在可微分編程
    這種工作方式讓調試工作變得非常困難,因為在網絡運行時,你沒法使用 Python 了解其中究竟發生了什麼。你也沒法使用 pdb 等方法。即使你想使用古老但好用的 print 調試方法,你也只能使用 tf.print 並在你的網絡中構建一個 print 節點,這又必須連接到網絡中的另一個節點,而且在 print 得到任何信息之前還必須進行編譯。不過也存在更加直接的解決方案。
  • Android安全防護之旅---幾行代碼讓Android應用變得更加安全
    這裡說的混淆不是說的傳統大家都知道的簡單混淆策略,而是高級一點的混淆策略,首先是代碼混淆,大家可以參考小黃車app的代碼:看到了吧人家把代碼混淆成中國人可以看懂的信息,可惜這樣的信息對於我們破解來說就很麻煩了,關於怎麼做到的,之前的文章已經介紹了,大家可以查閱這裡:Android中把代碼混淆成中文,當然可以簡單一點就是用 -classobfuscationdictionary
  • 小青和他的 RxSwift 課程
    沙龍的茶歇期間的閒聊,我才了解到小青還未大學畢業,但是他已經在 Enjoy 開始了他的第二份實習,而這份實習中,他將會用 RxSwift 重構 Enjoy 的眾多模塊。我私下問他為什麼選擇 Enjoy,他毫不猶豫地說:「因為可以用 RxSwift 呀!」。
  • 我不是一個寫死代碼的碼農,我是一名程式設計師
    每一個奮鬥在代碼海洋裡的程式設計師都值得為他鼓掌,來看看此時徒弟們奮鬥的瞬間,順便分享一下作為一個程式設計師應該具備什麼樣的自我修養?有人卻思考問題出現的可能性,使用排除法和調試法,先分析錯誤碼,再定位問題是出現在前端還是接口,定位出來之後,再對邏輯代碼進行調試分析,沒多久就把問題找到並且修復了bug。一份代碼的編寫,有人東拼西湊,面向過程式的編碼,最終實現功能後,代碼冗長易讀性差,自己也沒學到什麼東西。
  • 賽博朋克2077控制臺代碼大全 無限金幣技能點子彈生命代碼匯總
    賽博朋克2077控制臺代碼是多少?很多玩家都想知道賽博朋克2077無限金幣技能點子彈生命代碼!目前小編已經找到了相關的全部代碼。話不多說,下面,就隨琵琶網小編來了解一下吧!   在遊戲中,玩家想要使用無限代碼,需要先解鎖調試控制臺,具體的方法是:   1、創建記事本   2、打開——Cyberpunk 2077\engine\config\base\General.ini   3、加上—— DBGConsoleOn=true   重啟賽博朋克2077,玩家把下方的代碼打到新建的記事本裡,然後進入遊戲按
  • 有關Keil軟體仿真的51單片機串口調試技巧
    ② 串口軟體可以是自己編寫的專用調試或上下位機通信軟體,也可以是通用的串口軟體(如串口助手、串口調試等),主要用來收發數據。如果沒有合適的串口調試軟體,則可使用筆者編寫的一個免費的串口小工具TurboCom。除了與其他軟體一樣的數據收發功能外,它還有定時輪流發送自定義數據幀和自動應答(接收到指定數據幀後,自動返回相應的數據幀)這兩個很有用的功能,特別適合於老化測試。
  • 在C語言中用ASSERT調試的八個技巧
    想要理解上述斷言定義的開發人員應該留意下面三個要點:·斷言會評估一個表達式是真還是假·斷言是在代碼中的某個點對系統狀態的一種假設·斷言會驗證系統假設,如果不為真,就表明代碼中有一個缺陷技巧2:使用ASSERT驗證函數的先決條件斷言非常適合契約式設計環境,在這種環境中,開發人員非常清晰地定義了某個函數的先決條件
  • 使用 Swift 創建簡單的二維碼掃描應用
    在 Constants.swift 文件中,將https://api.discogs.com/database/search?q= 添加到常量 DISCOGS_AUTH_URL 中。拷貝 Consumer Key,粘貼到 Constants.swift 文件的 DISCOGS_KEY 中。再拷貝 Consumer Secret,粘貼到Constants.swift 文件的 DISCOGS_SECRET 中。同 URL 一樣,現在我們可以在應用中很方便地使用這些變量了。
  • 黴黴Taylor.swift近六年前任你知道幾個雷神弟弟??
    在12年七月份的時候,Taylor swift跟Conor Kennedy在一起了,可惜只有短短的三個月,三個月以後就分道揚鑣了,她為他創作了一首《begin again》,這首歌寫的是 Taylor swift在遍體鱗傷的感情之後,很長一段時間都不敢去愛其他的人,這時終於出現了一個人能讓她又一次敞開心扉
  • KTV調試的靈魂——話筒效果調試
    今天我們一起來探討KTV話筒效果聲的調試。 一、效果聲種類效果聲是從話筒聲中取出一部分進行加工(延時、重複等)後,再疊加到直達聲上的「裝飾音」,也稱之為「溼聲」。KTV前級效果器的話筒效果調試,相對專業效果器而言,要簡單很多。
  • 編寫一個Open Live Writer的VSCode代碼插件
    起因又是一年多沒有更新過博客了,最近用Arduino做了一點有意思的東西,準備寫一篇博客。打開塵封許久的博客園,發現因為Windows Live Writer停止更新,博客園推薦的客戶端變為了Open Live Writer(基於Windows Live Writer代碼,然而GitHub上的代碼已經快一年沒更新了)。
  • 你為什麼不能成為一個「直播寫代碼」的網紅?
    他也回復了Github上的issue,將一些錯誤分類,調試代碼分支。我覺得他這樣很有意思,因為Nolan維護著擁有很高使用頻率的開原始碼庫。我覺得他的開源生活和我很不一樣。你可以看到我曾經在他的視頻下留言: