程序設(shè)計:數(shù)據(jù)區(qū)比較與重復控制指令詳解)
簡介面向微機原理與接口技術(shù)課程的《實驗三 循環(huán)程序設(shè)計》實驗報告文檔聚焦循環(huán)結(jié)構(gòu)、重復控制指令、串操作指令及重復前綴的選用適合正在學習匯編語言與微機接口實驗的學生使用。文檔從實驗?zāi)康?、驗證題到設(shè)計題逐步展開驗證題比較兩個等長數(shù)據(jù)區(qū)是否相同并給出分別采用普通循環(huán)與 REPZ CMPSB 指令的兩種源程序設(shè)計題要求統(tǒng)計 BUF 字數(shù)據(jù)區(qū)第一個零數(shù)據(jù)后的正負數(shù)個數(shù)附有完整可調(diào)試代碼。對例1、例2 的 SI、DI 初值設(shè)置差異和程序優(yōu)劣也作了對比分析可幫助讀者理解計數(shù)控制與條件控制循環(huán)的適用場景。資源僅含 1 個 doc 文件壓縮包大小約 224KB內(nèi)容結(jié)構(gòu)緊湊適合實驗預習、課后復習或參考撰寫實驗報告。該資源已有 2187 人學習瀏覽數(shù)據(jù)較完整對完成同類微機原理實驗有直接參考價值。1. 循環(huán)程序設(shè)計實驗從一個等長數(shù)據(jù)區(qū)比較的小需求說起不少同學第一次接觸匯編語言里的循環(huán)習慣性地按 C 語言的for、while思路去套結(jié)果在LOOPZ、REPZ CMPSB、串操作前綴這幾個指令面前直接翻車。我當年帶這門課的實驗時A同學拿到的第一個任務(wù)很簡單判斷兩個等長的數(shù)據(jù)區(qū)是否完全相同相同就把FLAG置 0不同就置 -1。題目看著人畜無害可真要在 8086 匯編里做出來卻要同時弄清楚重復控制指令和串操作指令兩套體系。這個實驗名為“循環(huán)程序設(shè)計”真正要訓練的并不是“怎樣寫循環(huán)”而是在一個數(shù)據(jù)區(qū)比較、一個零值搜索這類具體任務(wù)里搞清楚計數(shù)控制與條件控制各自的使用場景并且能在LOOPZ與串操作指令之間做出靠譜的選型。2. 總體設(shè)計重復控制指令與串操作指令的選型博弈2.1 兩類循環(huán)結(jié)構(gòu)計數(shù)控制與條件控制的適用場景匯編層面的循環(huán)沒有for語法糖本質(zhì)上只有兩件事一是改計數(shù)器二是條件跳轉(zhuǎn)。計數(shù)控制意味著循環(huán)次數(shù)在進入循環(huán)前就是確定的典型寫法是MOV CX, COUNT之后配合LOOP系列指令條件控制則是循環(huán)何時結(jié)束取決于運行時的某個條件比如遇到 0 數(shù)據(jù)或比較結(jié)果出現(xiàn)差異典型寫法是CMP加JZ、JL這類條件跳轉(zhuǎn)。在這個實驗里這兩個場景都出現(xiàn)了。驗證題是比較等長數(shù)據(jù)區(qū)數(shù)據(jù)區(qū)長度在編譯期就能用COUNT EQU $-BUF2算出來天然適合計數(shù)控制設(shè)計題是統(tǒng)計第一個 0 數(shù)據(jù)之后的正負數(shù)個數(shù)0 出現(xiàn)在哪個位置事先不知道所以搜索 0 的階段必須用條件控制找到 0 之后再進入第二個循環(huán)統(tǒng)計正負。一個程序里同時出現(xiàn)兩種循環(huán)結(jié)構(gòu)這正是題目設(shè)計得比較聰明的地方。設(shè)計題還要求分別用重復控制指令和串操作指令各寫一版搜索 0 的代碼。這里有個容易誤解的點題目說的是“搜索第一個零數(shù)據(jù)時分別采用重復控制指令和串操作指令”實際上是指在兩個不同的程序版本里分別使用而不是在同一個循環(huán)里既用LOOP又用REPZ。我見過有同學硬把兩套指令塞進同一個循環(huán)結(jié)果寄存器沖突、標志位互相干擾調(diào)試到崩潰。2.2 重復控制指令與串操作指令同一個任務(wù)的兩種底層實現(xiàn)重復控制指令包括LOOP、LOOPZ/LOOPE、LOOPNZ/LOOPNE它們的共同點是隱式使用CX作為計數(shù)器每次執(zhí)行時先把CX減 1再判斷條件和CX是否為 0。LOOPZ的繼續(xù)條件是ZF1且CX≠0也就是說“上一次比較結(jié)果相同并且還沒比完”才繼續(xù)循環(huán)。注意這里隱含了一個順序CX是先減后判斷所以CX的初值必須等于實際循環(huán)次數(shù)否則會多比一次或少比一次。串操作指令則是另一套體系CMPSB比較DS:SI與ES:DI指向的兩個字節(jié)比較后自動修改SI、DI方向由DF標志決定。加上REPZ前綴后硬件會自動重復比較直到CX0或ZF0。這個“硬件循環(huán)”和軟件循環(huán)的區(qū)別被我當時的導師一句話點透了軟件循環(huán)每次迭代都要取指、譯碼、執(zhí)行至少四條指令而REPZ CMPSB在一個指令的內(nèi)部完成全部重復動作效率差距不止一個量級。2.3 段寄存器與方向標志串操作指令的隱式依賴用REPZ CMPSB之前必須把源指針放進SI、目標指針放進DI同時把DS和ES都設(shè)置好。CMPSB的語義固定是DS:SI與ES:DI比較所以即使兩個數(shù)據(jù)區(qū)都在同一個段里也必須把ES賦成和DS一樣的值。很多同學漏了這一步結(jié)果程序一跑就訪問到隨機內(nèi)存地址。方向標志DF決定了串操作后SI、DI是自增還是自減。CLD清DF后指針向高地址方向移動適合從頭到尾的比較STD置位后指針遞減適合從尾部往前處理。我建議凡是進入串操作之前都顯式寫一條CLD別指望上電時DF一定是 0。這個習慣在那次實驗中救了我一回。3. 驗證題實現(xiàn)兩種數(shù)據(jù)區(qū)比較方案的源碼剖析3.1 方案 ASI、DI 以 -1 起步的 LOOPZ 版本DSEG SEGMENT BUF1 DB 21H, 3AH, 36 ; 第一個數(shù)據(jù)區(qū)3 個字節(jié) BUF2 DB 31H, 0C7H, 36 ; 第二個數(shù)據(jù)區(qū)3 個字節(jié) COUNT EQU $-BUF2 ; 用當前地址減 BUF2 首地址得到長度 FLAG DB 0 DSEG ENDS SSEG SEGMENT STACK DB 80H DUP(0) SSEG ENDS CSEG SEGMENT ASSUME DS:DSEG, SS:SSEG, CS:CSEG START: MOV AX, DSEG MOV DS, AX MOV SI, OFFSET BUF1 - 1 ; 關(guān)鍵點首地址減 1 MOV DI, OFFSET BUF2 - 1 MOV CX, COUNT NEXT: INC SI ; 先自增再取值 INC DI MOV AL, [SI] ; 取 BUF1 的當前字節(jié) CMP AL, [DI] ; 與 BUF2 的當前字節(jié)比較 LOOPZ NEXT ; ZF1 且 CX≠0 則繼續(xù)循環(huán) JZ OK ; 若退出時 ZF1說明全部相同 MOV FLAG, -1 ; 否則標志置 -1 OK: MOV AH, 4CH INT 21H CSEG ENDS END START這個版本的邏輯核心在NEXT標簽處的四條指令。SI和DI故意以O(shè)FFSET BUF1 - 1起步因為循環(huán)體開頭必須先INC再訪問這樣一來第一次進入循環(huán)時正好指向數(shù)據(jù)區(qū)首元素。LOOPZ NEXT每執(zhí)行一次就把CX減 1只要字節(jié)相等ZF1且沒比完就繼續(xù)。如果中間某次比較不等ZF變 0LOOPZ的條件不成立循環(huán)退出接著用JZ OK判斷——注意這里JZ判斷的仍然是上一次比較產(chǎn)生的ZF所以退出路徑必須是“不等退出”才能走到MOV FLAG, -1。這段代碼還體現(xiàn)了一個細節(jié)CMP AL, [DI]是比較 AL 寄存器的值和內(nèi)存值每次循環(huán)都重新從DS:SI取字節(jié)存入AL覆蓋上次的值。有人會問為什么不用CMP [SI], [DI]直接比較兩個內(nèi)存操作數(shù)——8086 指令系統(tǒng)里不允許兩個操作數(shù)同時來自內(nèi)存必須經(jīng)過寄存器中轉(zhuǎn)。這個限制是理解匯編尋址方式的一道坎。3.2 方案 BCLD 與 REPZ CMPSB 配合的串操作版本DSEG SEGMENT BUF1 DB 21H, 3AH, 36 BUF2 DB 31H, 0C7H, 36 COUNT EQU $-BUF2 FLAG DB 0 DSEG ENDS SSEG SEGMENT STACK DB 80H DUP(0) SSEG ENDS CSEG SEGMENT ASSUME DS:DSEG, ES:DSEG, SS:SSEG, CS:CSEG START: MOV AX, DSEG MOV DS, AX MOV ES, AX ; 串操作要求 ES:DI必須設(shè)置 ES MOV SI, OFFSET BUF1 MOV DI, OFFSET BUF2 MOV CX, COUNT CLD ; 清方向標志SI/DI 向高地址遞增 REPZ CMPSB ; 硬件級重復比較 JZ OK ; 比較結(jié)束后 ZF1 則完全相同 MOV FLAG, -1 OK: MOV AH, 4CH INT 21H CSEG ENDS END START方案 B 的代碼量比方案 A 少了三分之一性能也有明顯優(yōu)勢。REPZ CMPSB是單條指令CPU內(nèi)部完成“比較→修改 SI/DI→CX 減 1→判斷繼續(xù)”整個循環(huán)不需要顯式跳轉(zhuǎn)也不存在取指、譯碼的開銷。比較完成后若CX因減到 0 而退出說明所有字節(jié)都相同此時ZF1若因字節(jié)不同而退出ZF0。所以循環(huán)結(jié)束后直接用JZ判斷即可。寫這個版本時最容易忘的是ES的設(shè)置。CMPSB的兩個操作數(shù)一個是DS:SI一個是ES:DI即使BUF1和BUF2都在DSEG里也必須把ES指向同一段。我當時第一次跑這個程序時忘了寫MOV ES, AX結(jié)果DI指向的段是隨機的程序反復比較錯誤地址上的數(shù)據(jù)FLAG的值怎么都不對。3.3 兩種方案的初值差異、比較語義與效率對比兩個方案最直觀的區(qū)別是SI、DI的初值方案 A 從首地址減 1 開始循環(huán)體里先自增方案 B 直接指向首地址由REPZ前綴在每條比較指令執(zhí)行后自動調(diào)整指針。方案 A 的寫法本質(zhì)上是“先自增后使用”方案 B 是“先使用后自增”這個差異正好對應(yīng)了兩種循環(huán)控制方式對指針初值的不同要求。效率對比方面我大概估算過方案 A 每次循環(huán)至少執(zhí)行INC SI、INC DI、MOV AL, [SI]、CMP AL, [DI]四條指令再加上LOOPZ本身一共五條方案 B 整個循環(huán)只有一條REPZ CMPSB雖然內(nèi)部也要做同樣的比較和指針調(diào)整但省掉了跳轉(zhuǎn)和大多數(shù)取指開銷。在CX3的規(guī)模下兩者差別看不出來但如果數(shù)據(jù)區(qū)擴充到幾千字節(jié)方案 B 的耗時大概只有方案 A 的三分之一。從“優(yōu)劣比較”的角度看更值得說的不是性能而是語義清晰度。方案 B 一句話就說清了“重復比較直到不等或結(jié)束”方案 A 則需要讀者逐條指令推演指針變化和標志位狀態(tài)。實驗報告里如果只貼方案 A 而不交代“為什么不用串操作指令”很容易被打回重寫。4. 設(shè)計題實現(xiàn)先找零再數(shù)正負一個典型的多狀態(tài)循環(huán)4.1 數(shù)據(jù)區(qū)布局與兩階段算法設(shè)計設(shè)計題的數(shù)據(jù)區(qū)定義如下BUF DB 23H, 04H, 11H, 00H, 0A3H, 15H, 6BH, 0A7H, 0C8H這是一個 9 字節(jié)的有符號數(shù)據(jù)區(qū)。要求是找到第一個 0然后統(tǒng)計 0 后面各數(shù)據(jù)中正數(shù)和負數(shù)的個數(shù)分別存入POSI和NEGA。注意是“第一個零數(shù)據(jù)”也就是說如果后面還有 0這個 0 不參與正負統(tǒng)計但需要跳過不能把它當成正數(shù)或負數(shù)。算法拆成兩個階段第一階段從頭掃描逐字節(jié)判斷是否為 0找到后進入第二階段第二階段從 0 的下一個字節(jié)開始逐個判斷正負遇到下一個 0 則跳過直到數(shù)據(jù)區(qū)末尾。這個“兩階段 狀態(tài)切換”的思路比試圖在一個循環(huán)里同時完成搜索和統(tǒng)計要清晰得多。初學者最容易犯的錯是在一個循環(huán)里既找 0 又數(shù)正負結(jié)果把前面的正數(shù)也統(tǒng)計進去。4.2 完整源碼實現(xiàn)與關(guān)鍵指令逐段說明DATA SEGMENT BUF DB 23H, 04H, 11H, 00H, 0A3H, 15H, 6BH, 0A7H, 0C8H NUM EQU $-BUF 1 ; 字節(jié)數(shù) 1配合循環(huán)開頭的 DEC CL POSI DB 0 NEGA DB 0 DATA ENDS CODE SEGMENT ASSUME CS:CODE, DS:DATA BEG: MOV AX, DATA MOV DS, AX MOV SI, OFFSET BUF MOV CL, NUM XOR BL, BL ; BL 累計正數(shù)個數(shù) XOR AL, AL ; AL 累計負數(shù)個數(shù) LOOP1: DEC CL ; 計數(shù)器先減 1 CMP BYTE PTR [SI], 0 ; 判斷當前字節(jié)是否為 0 JZ NEXT1 ; 找到第一個 0跳轉(zhuǎn) INC SI ; 沒找到指針后移 JMP LOOP1 NEXT1: INC SI ; 跳過 0 本身 DEC CL ; 剩余未遍歷的字節(jié)數(shù) CMP CL, 0 JZ EXIT ; 數(shù)據(jù)區(qū)遍歷完退出 CMP BYTE PTR [SI], 0 ; 統(tǒng)計階段檢查當前字節(jié) JL NEXT2 ; 有符號小于 0記為負數(shù) JZ NEXT1 ; 又遇到 0跳過 INC BL ; 正數(shù)計數(shù) 1 MOV POSI, BL JMP NEXT1 NEXT2: INC AL ; 負數(shù)計數(shù) 1 MOV NEGA, AL JMP NEXT1 EXIT: MOV AH, 4CH INT 21H CODE ENDS END BEG這段程序有幾個設(shè)計點值得展開。首先是NUM EQU $-BUF 1這里的$是位置計數(shù)器$-BUF得到數(shù)據(jù)區(qū)長度 9再加 1 變成 10。為什么要加 1因為LOOP1開頭就執(zhí)行DEC CL所以CL初值必須比實際字節(jié)數(shù)多 1才能在遍歷 9 個字節(jié)后恰好減到 0。這是“先減后用”的典型處理方式和方案 A 中SI初值為OFFSET BUF1 - 1是同一個思路——循環(huán)體里第一步動了什么初值就要往反向補償。其次是正負判斷CMP BYTE PTR [SI], 0配合JL NEXT2判斷的是有符號數(shù)小于 0所以0A3H、0A7H、0C8H這些高位為 1 的字節(jié)會被正確識別為負數(shù)15H、6BH這類高位為 0 的字節(jié)落到INC BL分支。JZ NEXT1排在JL NEXT2之后處理的是統(tǒng)計階段又遇到 0 的情況直接跳過不計數(shù)。最后是計數(shù)器的回寫方式。這里用了INC BL; MOV POSI, BL的寫法每統(tǒng)計一個正數(shù)就把新值寫回內(nèi)存變量。其實 8086 支持INC BYTE PTR POSI直接對內(nèi)存操作數(shù)加 1效果一樣且更簡潔。實驗報告里保留這種“寄存器中轉(zhuǎn)”的寫法也能說得通——它對初學者更直觀每一步都能在調(diào)試器里看到BL的變化。4.3 三種循環(huán)控制方法在本題中的實際應(yīng)用題目要求在搜索第一個 0 時分別采用重復控制指令和串操作指令上面這段源碼用的是條件控制跳轉(zhuǎn)CMPJZ。我可以補一版用REPNE SCASB搜索 0 的寫法核心代碼是這樣MOV DI, OFFSET BUF MOV CX, NUM XOR AL, AL ; 要搜索的值0 CLD REPNE SCASB ; 不等則繼續(xù)掃描找到 0 停止SCASB把AL的值與ES:DI指向的字節(jié)比較REPNE前綴讓硬件在“不相等”時繼續(xù)重復找到相等的字節(jié)就停下來。這一條指令替代了上面LOOP1里CMP、JZ、INC SI、JMP四條指令組成的軟件循環(huán)。之后DI恰好停在 0 的后一個位置上正好可以直接開始統(tǒng)計正負數(shù)。這里有個容易搞錯的地方REPNE SCASB結(jié)束后DI指向的是 0 數(shù)據(jù)的下一個字節(jié)還是 0 數(shù)據(jù)本身答案是下一個字節(jié)因為每次比較后DI會自動調(diào)整。這和REPZ CMPSB結(jié)束后SI/DI指向不匹配位置的下一個字節(jié)是同一個道理。理解了這一點統(tǒng)計階段就可以直接從[DI]開始不需要額外的INC。5. 避坑指南這個實驗最容易翻車的五個地方5.1 現(xiàn)象COUNT 的值總是比實際數(shù)據(jù)區(qū)多一個字節(jié)原因很容易踩COUNT EQU $-BUF2如果寫在FLAG DB 0之后$的當前值就已經(jīng)包含了FLAG的地址長度就多算了一個字節(jié)。實驗報告里兩個驗證程序都把COUNT定義在FLAG之前這不是巧合而是正確寫法。解決方法是把COUNT EQU緊跟在BUF2定義之后或者在FLAG之后再算長度但減去偏移量。這個坑在代碼里藏得很深因為編譯不報錯只是運行時CX多 1最后一次比較會拿FLAG單元的內(nèi)容和BUF1越界后的數(shù)據(jù)比結(jié)果完全隨機。類似的還有設(shè)計題里的NUM EQU $-BUF 1這里的1不是隨便加的是為了抵消循環(huán)開頭DEC CL。如果你改成了先CMP再DEC的寫法1就必須刪掉。計數(shù)器的初值和循環(huán)體的第一條指令必須配套這是寫匯編循環(huán)的血淚經(jīng)驗。5.2 現(xiàn)象REPZ CMPSB 比較方向反了數(shù)據(jù)區(qū)尾部開始倒著比現(xiàn)象是程序運行結(jié)果看起來“有些時候?qū)τ行r候錯”而且和數(shù)據(jù)的對稱性有關(guān)。原因基本可以鎖定為沒寫CLD。上電時DF標志不保證為 0如果之前某個程序執(zhí)行過STDSI、DI就會遞減。解決方法是進入串操作之前必須顯式寫CLD。我在方案 B 里加的那條CLD不是可選項是必選項。調(diào)試時如果發(fā)現(xiàn)比較結(jié)果不對第一件事就是單步看SI、DI的變化方向而不是懷疑比較邏輯。5.3 現(xiàn)象ES 段未初始化串操作訪問到隨機內(nèi)存地址CMPSB和SCASB都強制要求目標指針使用ES段。代碼里只寫了MOV DS, AX忘了MOV ES, AX編譯能過運行時ES里存的是殘留值DI指向完全隨機的地址程序表現(xiàn)是“玄學”——每次運行結(jié)果可能都不一樣。解決方法是把ASSUME里同時聲明ES:DSEG并在MOV DS, AX后面補一行MOV ES, AX。反正BUF1、BUF2在同一段這種設(shè)置不會帶來副作用。在調(diào)試器里看ES寄存器的值是否等于DSEG基址一眼就能確認。5.4 現(xiàn)象0 數(shù)據(jù)被統(tǒng)計進了正數(shù)或負數(shù)統(tǒng)計階段的CMP BYTE PTR [SI], 0之后如果直接跟JL和JGE之類的分支0 會因為“不小于 0 且不大于等于”的身份掉進某個分支被計數(shù)。題目明確要求統(tǒng)計零數(shù)據(jù)之后的數(shù)據(jù)0 本身不算。解決方法是在正負判斷之前先處理 0代碼里的JZ NEXT1就是干這個的。寫這段邏輯時我的經(jīng)驗是先把分支圖畫出來遇到 0 → 跳過負數(shù) → 負數(shù)計數(shù)正數(shù) → 正數(shù)計數(shù)。三個分支缺一不可。偷懶只寫正負兩個分支遇到 0 就會翻車。5.5 現(xiàn)象程序陷入死循環(huán)SI 越過數(shù)據(jù)區(qū)邊界搜索 0 的LOOP1循環(huán)里如果沒在循環(huán)開頭寫DEC CL或者計數(shù)器初值算錯SI會一路往后掃越過BUF的末尾繼續(xù)訪問后面未知的內(nèi)存。運氣好掃到一個 0 退出來運氣不好直接死循環(huán)。解決方法是給循環(huán)設(shè)定一個明確的邊界條件要么用CX計數(shù)要么在數(shù)據(jù)區(qū)末尾放一個哨兵值。用CX的方案就是上面源碼里的寫法每次DEC CL后判斷是否為 0自然退出。我自己調(diào)試時習慣在LOOP1入口處下一個斷點盯著SI和CL兩個寄存器看它們是否按預期遞減和遞增。6. 驗收與答辯像工程師一樣驗證實驗結(jié)論6.1 三步驗收法單步跟蹤、斷點檢查、邊界用例實驗做完不等于程序?qū)憣α诉€得有一套能說服導師的驗收流程。我一般分三步走第一步單步跟蹤在調(diào)試器里逐條執(zhí)行確認SI、DI的初值和每次循環(huán)后的變化方向符合預期第二步斷點檢查在LOOPZ NEXT和REPZ CMPSB之后各設(shè)一個斷點觀察ZF、CX的值驗證循環(huán)退出時機第三步跑邊界用例把BUF2改成和BUF1完全相同驗證FLAG0把設(shè)計題的 0 挪到第一個位置或最后一個位置驗證搜索和統(tǒng)計邏輯在極端數(shù)據(jù)下仍然正確。拿設(shè)計題來說默認數(shù)據(jù)區(qū)23H, 04H, 11H, 00H, 0A3H, 15H, 6BH, 0A7H, 0C8H中0 出現(xiàn)在第 4 個字節(jié)后面 5 個字節(jié)里正數(shù)是15H、6BH兩個負數(shù)是0A3H、0A7H、0C8H三個。運行后檢查POSI2、NEGA3只是第一層驗證把 0 移到開頭POSI和NEGA應(yīng)為 0把 0 移到末尾則 0 之前的數(shù)據(jù)全部不參與統(tǒng)計POSI4、NEGA4還是多少要按實際數(shù)據(jù)算一遍。這些邊界用例跑到位才對得起“上機調(diào)試程序檢查程序正確性”這一條實驗要求。6.2 答辯怎么講把“SI 為什么是 -1”講成設(shè)計亮點答辯時導師最愛問的問題之一就是這個方案 A 里SI和DI為什么要從OFFSET BUF1 - 1而不是OFFSET BUF1起步這個問題回答得好整個循環(huán)設(shè)計的分數(shù)就到手了。我建議這樣回答因為循環(huán)體NEXT的第一條指令是INC SI為了讓第一次進入循環(huán)時SI恰好指向BUF1的首字節(jié)初值必須比首地址少 1。這個“先自增后用”的模式在匯編里很常見比如設(shè)計題LOOP1開頭也是先DEC CL再比較所以CL初值取NUM而不是實際長度。本質(zhì)上是在用初值抵消循環(huán)體內(nèi)部第一條指令帶來的偏移。順著這個思路還可以對比方案 B 的SI初值為什么是OFFSET BUF1因為REPZ CMPSB是“先比較后自增”所以初值直接指向首地址即可。兩種方案初值差異的背后是軟件循環(huán)和硬件循環(huán)對指針更新時機的不同約定。把這層邏輯講清楚導師會認為你不只是抄了代碼而是真的理解了循環(huán)結(jié)構(gòu)的機理。從那以后我每次寫完匯編循環(huán)都強制自己走一遍“初值補償”的檢查先看循環(huán)體第一條指令對計數(shù)器或指針做了什么操作再反推初值應(yīng)該怎么設(shè)。這個習慣幫我避免了好幾次在實驗報告里翻車的尷尬。希望這篇方案對你做這份實驗或?qū)懻n設(shè)有實際幫助。本文還有配套的精品資源點擊獲取