2017-10-14 109 views
0

我正在編寫一個程序,詢問用戶他們有哪個溫度,然後接受該輸入並轉換並輸出所有四種溫度。我需要幫助讓我的用戶輸入讀入,以便它可以在我的分支beq中工作。我無法讓它識別輸入'f'等於存儲的版本。如何將存儲的字符串與輸入的字符串進行比較MIPS

.data  
temptype: .asciiz "Enter temperature type i.e. f, c, k, r: " 
tempdegree: .asciiz "\n Enter degrees: " 
space: .space 2 
tempx: .asciiz "Your temperature in celsius is: " 
tempc: .asciiz "\nYour temperature in celsius is: " 
tempf: .asciiz "\nYour temperature in fahrenheit is: " 
tempk: .asciiz "\nYour temperature in kelvin is: " 
tempr: .asciiz "\nYour temperature in rankine is: :" 
kr: .float 459.67 

.globl main 

.text 
    main: 

     li $v0, 4 
     la $a0, temptype 
     syscall 

     li $v0, 8 
     la $a0, space 
     #li $a1, 2 
     move $t0, $a0 
     syscall 

     li $t1, 102 
     #li $t1, 99 
     #li $t1, 107 
     #li $t1, 114 
     syscall 

     beq $t0, $t1, fahrenheit 
     #beq $t0, $t1, celsius 
     #beq $t0, $t1, kelvin 
     #beq $t0, $t1, rankine 
     syscall 

     li $v0,10 
     syscall 

    fahrenheit: 

     li $v0, 4 
     la $a0, tempdegree 
     syscall 

     li $v0, 5 
     syscall 

     move $t0, $v0 

     li $v0, 4 
     la $a0, tempf 
     syscall 

     move $a0, $t0 
     li $v0, 1 
     syscall 
+1

您是否在內置調試器中單步執行代碼?你是否檢查過你正在使用的系統調用的文檔,看它是否返回寄存器中的字符,或者是否將它存儲在內存中?您可能會將指針與數字或其他內容進行比較。 (你沒有評論你的代碼,我不知道MIPS模擬器的系統調用數字不在我的頭頂。)無論如何**使用調試器**,這將使得能夠更容易地檢查每個寄存器中'beq'正在看什麼。 –

回答

3

MIPS CPU(並且沒有其他任何一個共同的),沒有「比較字符串」指令,字符串不是原生類型的CPU和說明僅適用於原生類型,如單詞和字節處理。

「字符串」是連續字符的一定數量(或在數據末尾定義的某處,或使用終止符字符)。什麼是「一個字符」取決於使用的編碼,對於您的情況(MARS模擬器,以及簡單的asm編程練習),您可以使用舊的ASCII編碼,其中單個字符恰好是一個單個字節。 (JFYI:對於現代SW,你將主要使用UTF8編碼,就像這個網頁一樣,單個字符可以有不同的字節數,這取決於你編碼的字形,這使得通過UTF8編碼的字符串編程任何字符串算法變得更加有趣)

現在CPU寄存器是「字」大小,這意味着它們是32位「寬」,即它們最多可以容納4個ASCII字符(一次4個字節),所以使用寄存器來存儲整個字符串將只允許非常sho。海峽。和別的。你可以這樣做,但這是不實際的(除了beq會起作用,因爲你可以比較字值0x30303030 = "0000"0x31313131 = "1111"beq)。因此,大部分時間在MIPS初學者程序集編程時,「字符串」是以下模式:某些寄存器包含指向字符串的第一個字母(字符串的第一個字節)的內存地址,以及指向字符串的第一個字符的最後一個「字符」字符串不是任何字母,而是值爲零的所謂「空終止符」。

當你想比較字符串,然後,你創建循環,它開始於兩個指針(對兩個字符串=兩個第一個字母)。從兩個地址加載字節到一些臨時寄存器(即加載兩者的首字母),比較一下,如果它們不同,則字符串不同。如果相等,檢查零(兩個字符串結束=它們相等)。如果不是零,則將兩個地址前進一個,以便它們指向下一個字母,並循環到開頭。

但在您的情況下,用戶只能輸入單個字母,而您只想比較單個字母,因此編寫整個循環需要花費很多精力,您可以加載該單個字母並進行比較。

所以閱讀從上源,這些線路將得到我的意見:

#li $a1, 2 

被註釋掉爲什麼呢?你應該使用它來限制系統調用(我認爲沒有設置任何默認值可能爲零,所以沒有輸入發生)。你也許會對syscall(v0=12)「讀取字符」而不是「讀取字符串」感興趣,但我不確定這是如何在MARS中呈現給用戶的(用戶體驗相關),但讓我們堅持服務v0 = 8「讀取字符串」和2個字節長的緩衝區。

現在在syscall返回(用戶確實輸入字母「f」)後,地址space的內存將包含syscall:102,0設置的兩個字節。

li $t1, 102 

看起來很熟悉,但難以閱讀的其他程序員,與MARS彙編也可以用書面數是這樣的:li $t1, 'f' - 簡單的撇號告訴彙編你想單個ASCII字符的值('ab'是錯誤在MARS,只有單個字符,可以使用一些其他的彙編可以翻譯「AB」爲兩個字節值)

下一頁註釋掉的指令是:

syscall 

在這裏,你所要求的其中MA RS服務?您沒有在v0中設置任何值,也不需要任何服務,因此如果您在調試器中單步執行代碼,那麼如果您推斷每條指令會發生什麼情況,則這對您來說應該沒有意義。

然後來到beq $t0, $t1, fahrenheit

在這一點上t1等於'f',和t0等於緩衝器,在編譯期間也別名爲space符號,其等於大約32比特值的第一個字節的地址,大概類似於像0x100000c 。值0x100000c vs 102當然不等於,因此beq永遠不會跳轉到標籤fahrenheit

比較內部緩衝區的第一個字母,第一個從存儲器中取出它的價值,像lb $t2, ($t0),加載從地址t0(先進的信息字節值:lb將符號擴展8位到32位的值基本打印ASCII碼的字符都小於128,所以你不需要處理負值,但是如果字母'f'將編碼爲140,則使用lb將該值加載到t2將產生32位值-116而不是140 ..正如我寫的,基本的ASCII碼只有7位,所以只有正值,正如預期的那樣工作,102被裝載爲102)。

然後,您可以使用beq $t2, $t1, fahrenheit獲得更多成功,因爲現在它將比較ASCII字符和ASCII字符。

您也可以使用MARS MIPS彙編僞指令beq $t2, 'f', fahrenheit。火星將編譯爲兩個原生指令:

addi $at, $zero, 102 # 102 = 'f', $at = $1, $zero = $0 
beq $at, $t2, fahrenheit 

節省您的一些打字,這是在規劃好,只要它是有意義的,而讀(一旦你將開始縮短你的源代碼只是爲目的簡短的寫作,你做錯了,編程中的源代碼被寫入被讀取,寫入成本與閱讀成本相比可以忽略不計)。在這種情況下,beq $t2, 'f', label看起來對我來說很可讀,所以我更喜歡這樣。

而且這應該足以回答你的問題,明確的問題(如何比較字符串=在循環中,逐字符)和隱式的問題(如何比較用戶的單個字母與'f' )。

+0

minor quibble:x86有'repe cmpsb',它比較字符串,而x86很常見。它通常不是比較字符串的最高性能方式,而且您必須知道其中一個字符串的長度,否則它們將在兩個字符相同時結束時超過「0」字節。 stos/movs/lods/cmps/scas被稱爲字符串指令。 –

+0

@PeterCordes公平的狡辯......但由於這個問題的背景和OP的預期技能水平,我認爲在評論中保留它可能是最好的,我已經試圖將額外的信息放在帶有免責聲明的括號中,但我仍然有些擔心OP會像TLDR一樣超過重要的位... OP:如果TLDR,這裏是總結:**使用調試器** – Ped7g

+0

@ Ped7g謝謝!我得到了它的工作。您的回覆非常豐富。 –

相關問題