<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                # 25章 溫度轉換 另一個在初學者的編程書中常見的例子是溫度轉換程序,例如將華氏度轉為攝氏度,或者反過來。 我也添加了一個簡單的錯誤處理: 1)我們應該檢查用戶是否輸入了正確的數字 2)我們應該檢查攝氏度是否低于-273゜C,因為這比絕對零度還低,學校物理課上的東西應該都還記得。 exit()函數將立即終止程序,而不會回到調用者函數。 ## 25.1 整數值 ``` #!cpp #include <stdio.h> #include <stdlib.h> int main() { int celsius, fahr; printf ("Enter temperature in Fahrenheit:\n"); if (scanf ("%d", &fahr)!=1) { printf ("Error while parsing your input\n"); exit(0); }; celsius = 5 * (fahr-32) / 9; if (celsius<-273) { printf ("Error: incorrect temperature!\n"); exit(0); }; printf ("Celsius: %d\n", celsius); }; ``` ### 25.1.1 MSVC 2012 x86 /Ox 清單25.1: MSVC 2012 x86 /Ox ``` #!bash $SG4228 DB ’Enter temperature in Fahrenheit:’, 0aH, 00H $SG4230 DB ’%d’, 00H $SG4231 DB ’Error while parsing your input’, 0aH, 00H $SG4233 DB ’Error: incorrect temperature!’, 0aH, 00H $SG4234 DB ’Celsius: %d’, 0aH, 00H _fahr$ = -4 ; size = 4 _main PROC push ecx push esi mov esi, DWORD PTR __imp__printf push OFFSET $SG4228 ; ’Enter temperature in Fahrenheit:’ call esi ; call printf() lea eax, DWORD PTR _fahr$[esp+12] push eax push OFFSET $SG4230 ; ’%d’ call DWORD PTR __imp__scanf add esp, 12 ; 0000000cH cmp eax, 1 je SHORT $LN2@main push OFFSET $SG4231 ; ’Error while parsing your input’ call esi ; call printf() add esp, 4 push 0 call DWORD PTR __imp__exit $LN9@main: $LN2@main: mov eax, DWORD PTR _fahr$[esp+8] add eax, -32 ; ffffffe0H lea ecx, DWORD PTR [eax+eax*4] mov eax, 954437177 ; 38e38e39H imul ecx sar edx, 1 mov eax, edx shr eax, 31 ; 0000001fH add eax, edx cmp eax, -273 ; fffffeefH jge SHORT $LN1@main push OFFSET $SG4233 ; ’Error: incorrect temperature!’ call esi ; call printf() add esp, 4 push 0 call DWORD PTR __imp__exit $LN10@main: $LN1@main: push eax push OFFSET $SG4234 ; ’Celsius: %d’ call esi ; call printf() add esp, 8 ; return 0 - at least by C99 standard xor eax, eax pop esi pop ecx ret 0 $LN8@main: _main ENDP ``` 關于這個我們可以說的是: ``` ?printf()的地址先被載入了ESI寄存器中,所以printf()調用的序列會被CALL ESI處理,這是一個非常著名的編譯器技術,當代碼中存在多個序列調用同一個函數的時候,并且/或者有空閑的寄存器可以用上的時候,編譯器就會這么做。 ?我們知道ADD EAX,-32指令會把EAX中的數據減去32。 EAX = EAX + (-32)等同于 EAX = EAX - 32,因此編譯器決定用ADD而不是用SUB,也許這樣性能比較高吧。 ?LEA指令在值應當乘以5的時候用到了: lea ecx, DWORD PTR [eax+eax*4]。 是的,i + i * 4是等同于i*5的,而且LEA比IMUL運行的要快。 還有,SHL EAX,2/ ADD EAX,EAX指令對也可以替換這句,而且有些編譯器就是會這么優化。 ?用乘法做除法的技巧也會在這兒用上。 ?雖然我們沒有指定,但是main()函數依然會返回0。C99規范告訴我們[15章, 5.1.2.2.3] main()將在沒有return時也會照常返回0。 這個規則僅僅對main()函數有效。 雖然MSVC并不支持C99,但是這么看說不好他還是做到了一部分呢? ``` ## 25.1.2 MSVC 2012 x64 /Ox 生成的代碼幾乎一樣,但是我發現每個exit()調用之后都有INT 3。 ``` #!bash xor ecx, ecx call QWORD PTR __imp_exit int 3 ``` INT 3是一個調試器斷點。 可以知道的是exit()是永遠不會return的函數之一。所以如果他“返回”了,那么估計發生了什么奇怪的事情,也是時候啟動調試器了。 ## 25.2 浮點數值 清單11.1: MSVC 2010 ``` #!cpp #include <stdio.h> #include <stdlib.h> int main() { double celsius, fahr; printf ("Enter temperature in Fahrenheit:\n"); if (scanf ("%lf", &fahr)!=1) { printf ("Error while parsing your input\n"); exit(0); }; celsius = 5 * (fahr-32) / 9; if (celsius<-273) { printf ("Error: incorrect temperature!\n"); exit(0); }; printf ("Celsius: %lf\n", celsius); }; ``` MSVC 2010 x86使用FPU指令... 清單25.2: MSVC 2010 x86 /Ox ``` #!bash $SG4038 DB ’Enter temperature in Fahrenheit:’, 0aH, 00H $SG4040 DB ’%lf’, 00H $SG4041 DB ’Error while parsing your input’, 0aH, 00H $SG4043 DB ’Error: incorrect temperature!’, 0aH, 00H $SG4044 DB ’Celsius: %lf’, 0aH, 00H __real@c071100000000000 DQ 0c071100000000000r ; -273 __real@4022000000000000 DQ 04022000000000000r ; 9 __real@4014000000000000 DQ 04014000000000000r ; 5 __real@4040000000000000 DQ 04040000000000000r ; 32 _fahr$ = -8 ; size = 8 _main PROC sub esp, 8 push esi mov esi, DWORD PTR __imp__printf push OFFSET $SG4038 ; ’Enter temperature in Fahrenheit:’ call esi ; call printf lea eax, DWORD PTR _fahr$[esp+16] push eax push OFFSET $SG4040 ; ’%lf’ call DWORD PTR __imp__scanf add esp, 12 ; 0000000cH cmp eax, 1 je SHORT $LN2@main push OFFSET $SG4041 ; ’Error while parsing your input’ call esi ; call printf add esp, 4 push 0 call DWORD PTR __imp__exit $LN2@main: fld QWORD PTR _fahr$[esp+12] fsub QWORD PTR __real@4040000000000000 ; 32 fmul QWORD PTR __real@4014000000000000 ; 5 fdiv QWORD PTR __real@4022000000000000 ; 9 fld QWORD PTR __real@c071100000000000 ; -273 fcomp ST(1) fnstsw ax test ah, 65 ; 00000041H jne SHORT $LN1@main push OFFSET $SG4043 ; ’Error: incorrect temperature!’ fstp ST(0) call esi ; call printf add esp, 4 push 0 call DWORD PTR __imp__exit $LN1@main: sub esp, 8 fstp QWORD PTR [esp] push OFFSET $SG4044 ; ’Celsius: %lf’ call esi add esp, 12 ; 0000000cH ; return 0 xor eax, eax pop esi add esp, 8 ret 0 $LN10@main: _main ENDP ``` 但是MSVC從2012年開始又改成了使用SIMD指令: 清單25.3: MSVC 2010 x86 /Ox ``` #!bash $SG4228 DB ’Enter temperature in Fahrenheit:’, 0aH, 00H $SG4230 DB ’%lf’, 00H $SG4231 DB ’Error while parsing your input’, 0aH, 00H $SG4233 DB ’Error: incorrect temperature!’, 0aH, 00H $SG4234 DB ’Celsius: %lf’, 0aH, 00H __real@c071100000000000 DQ 0c071100000000000r ; -273 __real@4040000000000000 DQ 04040000000000000r ; 32 __real@4022000000000000 DQ 04022000000000000r ; 9 __real@4014000000000000 DQ 04014000000000000r ; 5 _fahr$ = -8 ; size = 8 _main PROC sub esp, 8 push esi mov esi, DWORD PTR __imp__printf push OFFSET $SG4228 ; ’Enter temperature in Fahrenheit:’ call esi ; call printf lea eax, DWORD PTR _fahr$[esp+16] push eax push OFFSET $SG4230 ; ’%lf’ call DWORD PTR __imp__scanf add esp, 12 ; 0000000cH cmp eax, 1 je SHORT $LN2@main push OFFSET $SG4231 ; ’Error while parsing your input’ call esi ; call printf add esp, 4 push 0 call DWORD PTR __imp__exit $LN9@main: $LN2@main: movsd xmm1, QWORD PTR _fahr$[esp+12] subsd xmm1, QWORD PTR __real@4040000000000000 ; 32 movsd xmm0, QWORD PTR __real@c071100000000000 ; -273 mulsd xmm1, QWORD PTR __real@4014000000000000 ; 5 divsd xmm1, QWORD PTR __real@4022000000000000 ; 9 comisd xmm0, xmm1 jbe SHORT $LN1@main push OFFSET $SG4233 ; ’Error: incorrect temperature!’ call esi ; call printf add esp, 4 push 0 call DWORD PTR __imp__exit $LN10@main: $LN1@main: sub esp, 8 movsd QWORD PTR [esp], xmm1 push OFFSET $SG4234 ; ’Celsius: %lf’ call esi ; call printf add esp, 12 ; 0000000cH ; return 0 xor eax, eax pop esi add esp, 8 ret 0 $LN8@main: _main ENDP ``` 當然,SIMD在x86下也是可用的,包括這些浮點數的運算。使用他們計算起來也確實方便點,所以微軟編譯器使用了他們。 我們也可以注意到 -273 這個值會很早的被載入XMM0。這個沒問題,因為編譯器并不一定會按照源代碼里面的順序產生代碼。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看