中国DOS联盟论坛

中国DOS联盟

-- 联合DOS 推动DOS 发展DOS --

联盟域名:www.cn-dos.net  论坛域名:www.cn-dos.net/forum
DOS,代表着自由开放与发展,我们努力起来,学习FreeDOS和Linux的自由开放与GNU精神,共同创造和发展美好的自由与GNU GPL世界吧!

游客:  注册 | 登录 | 命令行 | 会员 | 搜索 | 上传 | 帮助 »
中国DOS联盟论坛 » DOS批处理 & 脚本技术(批处理室) » dos 中的堆栈技术-----极其重要
作者:
标题: dos 中的堆栈技术-----极其重要 上一主题 | 下一主题
5yue5
初级用户





积分 69
发帖 34
注册 2009-2-8
状态 离线
『楼 主』:  dos 中的堆栈技术-----极其重要

-------我---对call  echo-----的研究-----------------------------------
1---call的标准用法
例子1:
  call :a
  goto:eof
:a
:echo 123
例子2:
call :a  123
goto:eof
:a
echo %1

把例子1,2合并,写成一种非标形式:
例子1------>call echo 123----回显123
例子2----->call echo %1---如果保存文件为nn.bat,输入nn 123 ,则回显123
例子3-----call echo %%i ---回显 i---说明脱掉了2个%号,call和echo个脱掉一个
所以 call echo 实际是调用子程序的简写,这样就很容易解释,call有延迟环境变量的功能,但是它并没有
开启延迟环境变量。只是调用了子程序的结果。
2-----call在for中的实例
for %%i in (0 1 2) do (
set t=%%i
echo %t%
)
由于bat是解释执行的,最后就只显示---->2

再看:
call :a
goto:eof
:a
set t=123
for %%i in (0 1 2) do (
set t=%%i
echo %t%
)

回显---》123 123 123,这是因为cmd执行的是解释程序。
改一改
call:a %t%
goto:eof
:a
set t=123
for %%i in (0 1 2) do (
set t=%%i
echo %1
)

这时call 调用子程序的参数,,回显----》2 2 2
上一句call调用的是for执行前的结果,这句调用的是for执行后的结果
由此,的结论:要调用for执行后的结果,应该调用子程序的参数。

再改一改上一句
@echo off
set t=123
for %%i in (0 1 2) do (
set t=%%i
call:a
:a
echo %t%
)
此时显示----》0 123 1 123 2 123这句说明了call可以让数据指针在for语句执行中,跟着for一起舞动,但是for执行完之后,它又回复到了
初始状态。call的这个功能相当于延迟环境变量的功能,但是它没有开启延迟环境变量,我以前的认识是错误的。
因为延迟变量传递值的时间比call早。这句话没法控制数据指针%t%返回到 t=123,无论你把goto:eof加到那里都不行。这是因为call这个支点会把前面的数据推入堆栈,call后就会自动把原来的数据从堆栈里面弹出,这样我们就看到了0 123 1 123 2 123这种数据的舞蹈。遗憾的是bat没有控制堆栈的语句。经过无数人的研究,发现了一种病态的写法来解决这个问题。
再改一改:

@echo off
set t=123
for %%i in (0 1 2) do (
set t=%%i
call echo %%t%%
)
此时回显-----》0 1 2
   原因如下:因为call执行的原理是把它前面的结果先推入堆栈,然后进入分支点,把分支点的内容执行完后,就从堆栈里面弹出保存的数据,然后回到call的下一个支点,继续前进。
  上面语句虽然是病态的,但是那个多加的%号,刚好然call麻醉了。多的那个%号,call认为,它推入堆栈的数据应该是从for开始的数据,for每循环一次的数据 ,call都把它推入堆栈,call执行完子程序后(就是这个病态写法里面的echo %%t%%),就会从堆栈里面弹出数据,然后执行它的下一句,就是进入for的下一次循环。 call语句中数据指针%t%始终指向的是存储单元t  ,for每次循环的值都是放在t存储单元的。从而就动态的看到了t值的变话。方法虽病态,这也是没办法的办法,随叫微软不弄个管理堆栈的命令。延迟环境变量利用的应该也是堆栈技术。setlocal enabledelayedexpansion这句话,就是把前面的数据推入到堆栈。endlocal 就是把推入堆栈的数据弹出来。%t% ,!t! 为数据指针,指向的是存储单元t,所以 call推入堆栈的数据是for的数据。

[ Last edited by 5yue5 on 2009-3-1 at 04:30 ]

   此帖被 +5 点积分    点击查看详情   
评分人:【 HAT 分数: +2  时间:2009-2-21 04:12
评分人:【 523066680 分数: +3  时间:2009-2-22 11:35


2009-2-17 18:38
查看资料  发送邮件  访问主页  发短消息 网志   编辑帖子  回复  引用回复
wangfangjian
中级用户





积分 274
发帖 192
注册 2009-1-7
状态 离线
『第 2 楼』:  

那支持普通的运算吗  
比如乘除 加减 成方等

2009-2-20 22:15
查看资料  发送邮件  发短消息 网志   编辑帖子  回复  引用回复
5yue5
初级用户





积分 69
发帖 34
注册 2009-2-8
状态 离线
『第 3 楼』:  问题集合

set /a tt=2+5   
set /a tt=2*5
set /a tt=7/2
set /a tt=7%2
set /a tt<<=1   -----乘2
set /a tt>>=1  ---除2
set /a tt+=1  ---每次累加1
还可以进行与或非等运算。
但是最难理解的是取反“~”运算。
set /a tt=~12 结果是-13
set /a tt=~(-12) 结果是11
也就是说decimal进制(10)的取反,在这里就是:加1再取负。
但是binary(2)进制的取反是直接取反。
如果对这些什么与或非运算,什么反码,补码不熟悉的话,不要紧的,你也不用去专门学习,这里不是搞汇编。你调用你本机的计算器练习这些运算就足以理解上面那些运算的含义了。


-----------------------------------------------------------
1-------
   把文字:/中国人爱好和平你好吗/到过来




@echo off
set x=中国人爱好和平你好吗
setlocal enabledelayedexpansion
for /l %%i in (8 -1 0) do (
  set/p tt=!x:~%%i,1!<nul
)

@echo off
set x=中国人爱好和平你好吗
setlocal enabledelayedexpansion
for /l %%i in (8 -1 0) do (
  set/p tt=!x:~%%i,1!
  set /p=!tt!
)

@echo off
set x=中国人爱好和平你好吗
setlocal enabledelayedexpansion
for /l %%i in (8 -1 0) do (
  set/p tt=!x:~%%i,1!
  set /p=!tt!<nul
)

2--------------
   以0-9十个数码为平面坐标,请显示全部可能的坐标。


@echo off
for /l %%1 in (0 1 9) do (
for /l %%2 in (0 1 9) do (
echo ^(%%1,%%2^)
  )
)
3---------------
上面的程序显示的坐标是成一列(竖)显示的,如何,让显示成为横向显示?

[ Last edited by 5yue5 on 2009-2-23 at 14:02 ]

2009-2-21 02:03
查看资料  发送邮件  访问主页  发短消息 网志   编辑帖子  回复  引用回复
523066680
银牌会员

SuperCleaner


积分 2362
发帖 1133
注册 2008-2-2
状态 离线
『第 4 楼』:  

很详细很有耐心  希望看的人也有同样的耐心。



综合型编程论坛

我的作品索引
  
2009-2-22 11:35
查看资料  发送邮件  访问主页  发短消息 网志  OICQ (523066680)  编辑帖子  回复  引用回复
wangfangjian
中级用户





积分 274
发帖 192
注册 2009-1-7
状态 离线
『第 5 楼』:  

很详细  谢谢

2009-2-22 21:29
查看资料  发送邮件  发短消息 网志   编辑帖子  回复  引用回复
5yue5
初级用户





积分 69
发帖 34
注册 2009-2-8
状态 离线
『第 6 楼』:  微软的官方 环境变量 描述原文翻译

http://technet.microsoft.com/en-us/library/bb490954.aspx   ---微软官方网站
  关于环境变量这段话的翻译,


Substituting environment variable values
取代环境变量的值
To enable the substitution of variable values at the command line or in scripts,
在命令行或脚本中是能够取代环境变量的值的
enclose the variable name in percent signs (that is, %variablename%).
用百分号包围变量名(如:%variablename%)
By using percent signs,
靠使用百分号
you ensure that Cmd.exe references the variable values instead of making a literal
comparison.
你保证可以使用cmd.exe参考变量的值,以取代创建的文字比较。
After you define variable values for a variable name,
在你为变量名定义了变量的值之后,
enclose the variable name in percent signs.
在百分号包围了变量名之后。
Cmd.exe searches for all instances of the variable name and replaces it with the defined variable value.
cmd会搜查所有变量名的实例,并且用定义的值取代它。
For example, if you create a script that contains different values (for example, user names)
and you want to define the USERNAME environment variable for each user with these values,
例如:如果你创建了一个脚本,它包含了不同的值(比如,若干用户名),并且你要定义用户名环境变量,
为每一个要使用这些值的用户,
you can write one script using the variable USERNAME enclosed in percent signs.
你能够使用被百分号包围的变量名写一个脚本。
When you run this script,
当你运行这个脚本时,
Cmd.exe replaces %USERNAME% with the variable values,
cmd就用变量的值取代%USERNAME% ,
which eliminates the need to perform this task manually for each user. Variable substitution is not recursive.
它排除了每个用户手工去完成这个任务,变量的取代不是递归的。

Cmd.exe checks variables once. For more information about variable substitution, see For and Call

cmd立即检查全部变量。需要更多的关于变量取代的信息,看for和call

Note
注释
The maximum individual environment variable size is 8192bytes.
最大的当环境变量的大小是8192b
The maximum total environment variable size for all variables, which includes variable names and the equal sign, is 65,536KB.
最大的全部环境变量的大小是,包括名字,等号,为65536kb



  我实验过,环境变量值的最大长度只能为8185,还有7过字节是保留字节,无法使用。

[ Last edited by 5yue5 on 2009-3-1 at 04:13 ]

2009-2-24 18:29
查看资料  发送邮件  访问主页  发短消息 网志   编辑帖子  回复  引用回复

请注意:您目前尚未注册或登录,请您注册登录以使用论坛的各项功能,例如发表和回复帖子等。


可打印版本 | 推荐给朋友 | 订阅主题 | 收藏主题



论坛跳转: