批處理位運算演示代碼

在論壇裡看到netbenton的那個不用call調用函數的帖子(下面貼有鏈接)後,突然記起以前自己寫的一個位運算演示的代碼(用call來調用函數,現改用netbenton的方法另類的調用),現拿出來和大傢分享一下,希望能給初學者一些小小的幫助

@echo off
title 位運算示例   code by:cn-bathome-more
echo.
echo.位運算名詞解釋(個人理解):
echo.
echo.位運算: 按操作數在計算機內表示的二進制數逐位進行邏輯運算或移位運算.
echo.與:   全部都是1才為1(指返回值,下同),否則為0.
echo.或:   隻要有1則為1,否則為0.
echo.異或: 不同為1,相同為0.
echo.取反: 是1則0,是0則1(單目運算符).
echo.取負: 先取反再加1(單目運算符).
echo.左移n位: 相當於乘以2的n次方(用0補位).
echo.右移n位: 相當於除以2的n次方(負數用1補位,正數用0補位).
echo.
echo.下面的示例是在三十二位系統(數值范圍:-2147483648~2147483647)下運行的結果.
echo.請輸入批處理能處理的數值(整數),否則將不能正確處理.如發生溢出,結果也不會正確.
echo.
rem 將十進制轉換為二進制的函數.
set "fun_d2b=setlocal enabledelayedexpansion&(for /l %%a in (0 1 31) do (set /a "str=!#a#!^>^>%%a"&set /a "str^&=1"&set "str_d2b=!str!!str_d2b!"))&(for %%a in (!str_d2b!) do (endlocal&set #a#=%%a))"
setlocal enabledelayedexpansion
:agn
set in=&set /p in=請輸入兩個數(中間用空格隔開):
if not defined in exit
set n=0
for %%a in (%in%) do (
   set /a n+=1
   set /a num!n!=%%a 2>nul
)
cls
echo.輸入的兩個數的有效數值為: "!num1!" 和 "!num2!", 用二進制表示分別為:
set /a str1=num1,str2=num2
%fun_d2b:#a#=str1%
%fun_d2b:#a#=str2%
echo.&echo.!str1!  ==^> !num1!
echo.!str2!  ==^> !num2!
echo.&echo.各種位運算的結果如下:
set /a "num=!num1!&!num2!,t=num"
%fun_d2b:#a#=num%&echo.&echo.!num! ==^> 按位與:   !num1! ^& !num2! = !t!
set /a "num=!num1!|!num2!,t=num"
%fun_d2b:#a#=num%&echo.&echo.!num! ==^> 按位或:   !num1! ^| !num2! = !t!
set /a "num=!num1!^^!num2!,t=num"
%fun_d2b:#a#=num%&echo.&echo.!num! ==^> 按位異或: !num1! ^^^^ !num2! = !t!
set /a "num=~!num1!,t=num"
%fun_d2b:#a#=num%&echo.&echo.!num! ==^> 按位取反:    ~(!num1!) = !t!
set /a "num=-!num1!,t=num"
%fun_d2b:#a#=num%&echo.&echo.!num! ==^> 取負:        -(!num1!) = !t!
set /a "ran=%random%%%5+2,num=!num1!,num<<=ran,t=num"
%fun_d2b:#a#=num%&echo.&echo.!num! ==^> 左移!ran!位:   !num1! ^<^< !ran! = !t!
set /a "ran=%random%%%5+2,num=!num1!,num>>=ran,t=num"
%fun_d2b:#a#=num%&echo.&echo.!num! ==^> 右移!ran!位:   !num1! ^>^> !ran! = !t!
echo.&goto :agn

批處理函數的高效另類應用(免call的哦!)

高速的真正的批處理函數應用方法!
並非調用子過程。。。

我想這次應該可以把批處理編程推向一個新的臺階。
目前隻支持一個參數,

@echo off
::定義函數
set "d-h=setlocal enabledelayedexpansion&set/a dx=#a#&set xs=0123456789abcdef&(for /l %%z in (1,1,4) do set /a x%%z=dx%%16,dx=dx/16)&(for /f "tokens=1-4" %%1 in ("!x1! !x2! !x3! !x4!") do set hx=!xs:~%%4,1!!xs:~%%3,1!&(if !hx!==00 set hx=)&(for %%z in ("!hx!!xs:~%%2,1!!xs:~%%1,1!") do endlocal&set #a#=%%~z))"
::10進制轉為16進制的函數,參數入口#a#
::要在開啟變量延遲之前定義
setlocal enabledelayedexpansion
for /l %%a in (1,7,1024) do (
    set abc=%%a
    
(%d-h:#a#=abc%)
rem 函數調用

echo !abc!
)
pause

可以支持多參數瞭
len函數為兩個參數,

@echo off

::定義函數
set "d-h=setlocal enabledelayedexpansion&set/a dx=#a#&set xs=0123456789abcdef&(for /l %%z in (1,1,4) do set /a x%%z=dx%%16,dx=dx/16)&(for /f "tokens=1-4" %%1 in ("!x1! !x2! !x3! !x4!") do set hx=!xs:~%%4,1!!xs:~%%3,1!&(if !hx!==00 set hx=)&(for %%z in ("!hx!!xs:~%%2,1!!xs:~%%1,1!") do endlocal&set #a#=%%~z))"
::10進制轉為16進制的函數,調用方法:%d-h:#a#=變量名%

set "len=for /f "tokens=1-3" %%1 in ("#a#") do setlocal enabledelayedexpansion&(if defined %%2 (set /a z=8180,x=0&(for /l %%a in (1,1,14) do set/a "y=(z-x)/2+x"&(for %%b in (!y!) do if "!%%2:~%%b,1!" equ "" (set/a z=y) else (set/a x=y)))) else (set z=0))&(for %%z in ("!z!") do endlocal&set %%1=%%~z)"
::取字符串長度函數,調用方法:%len:#a#=結果變量名 字符串變量名%
setlocal enabledelayedexpansion

for /l %%a in (1,7,1024) do (
    set abc=%%a

        (%len:#a#=slen abc%)
        (%d-h:#a#=abc%)
        (%len:#a#=dlen abc%)
        rem 函數調用
        
        echo %%a轉成16進制為:!abc!   轉換前字符數:!slen!  轉換後字符數:!dlen!
)
pause

思路確實夠新
但是因為兩個原因不建議推廣
代碼的可閱讀性降低
環境變量的過分使用也會影響效率

對於函數的效率問題
我覺得還是傳統的”goto對“來得更加簡單、自由和高效

通常情況下

應該避免在組合語句(括號對中的語句)中使用函數
如果綜合權衡後還是要使用
那麼就需要保證組合語句的循環和遞歸級數滿足設計要求

這種方法,對於函數的內部結構,可讀性是很差,但是對於主程序的可讀性卻表現得非常好

看:
(%len:#a#=slen abc%)
調用用函數len,作用是,計算變量abc中字符串的長度,把結果存到變量slen中

使用函數的作用不就是為瞭簡化主程序嗎?
而對於函數,通常都是引用前人或者自己常用的功能代碼,隻要根據註釋使用就可以瞭,
根本就不必去理會函數的內部做瞭什麼。就像其它編程語言調用api和dos中斷一樣,難道還要去瞭解其內部是怎麼運行的嗎?

有瞭這種函數,就算是批處理新手,也可以輕松寫出高效的批處理來,
就算是老手要寫較大型的批程序時,這些可是很好的磚瓦啊。
這種函數定義隻要一行就可以瞭,不足處是要占用一個變量名,和環境變量空間,但是這對於效率來說,這點是微小的,因為一個call :sub子過程用時相當於30層的call,及執行300次的set var=n,當然有一點,call sub.bat這種用法,要比call :sub 批處理內部子過程要快一半,但也是比用%len:#a#=var%多出來的時間,效率可想而知瞭。

經過這樣封裝的函數,是不可能會破壞主程序的結構的,4樓對len函數的使用,主程序和函數同進使用瞭同一個for令牌%%a卻一樣可以得到正確的結果。函數內部的變量使用完全是臨時的,在函數結束時已經用endlocal清場,隻保存返回結果。

想說些贊美的話,不好說出口。在一次創作中,突然想起netbenton這種函數的用法,於是也山寨瞭一個,呵呵。確實如樓主所言,發展一些高效的、正確的、常用的函數很有必要,能夠充分擴展批處理的功能,使得批處理累積起更大的功能,從而實現更高的跨越式的發展。

對於重復命令調用處理的方法和技術,目前看來有幾種:
1、復制粘貼,重復出現。這種模式在執行任務與命令比較少的情況下可以使用,比如使用echo產生兩三行空行,總比使用for產生的劃算吧?這種模式的結果是造成大量重復代碼,缺乏效率。
2、使用標簽,GOTO跳轉。把那些反復使用的同一功能段的代碼做成一個標簽,然後使用goto跳轉,這是最基本的模式。但goto隻負責跳出去而不跳回來,要想代碼自動回來則需要再跳一次。
3、使用標簽,Call調用。call的好處是跳到其他標簽後能夠自動跳回來。之所以能夠自動跳回來,因為call在原來代碼後面使用瞭標記,可能使用瞭更多的內存存儲來暫停原來的進程。所以,相對而言,會顯得較慢一些。但Call對參數有很好的支持,使得人們對其無法割舍。
4、使用FOR命令,化繁為簡。將那些符合FOR特性的命令融合到FOR當中,即可減少必要的重復操作。
5、使用函數,擴大變量。將一些命令組合賦值到某一個特定的變量中,變成通用函數,支持參數,它不需要重新建立標簽,但它占據瞭一個變量空間。這種模式適用於所賦值的命令組合比較簡短,占用空間不大的變量函數中。可以方便封裝以用於不同的批處理程序中。

推薦閱讀: