[新手上路]批处理新手入门导读[视频教程]批处理基础视频教程[视频教程]VBS基础视频教程[批处理精品]批处理版照片整理器
[批处理精品]纯批处理备份&还原驱动[批处理精品]CMD命令50条不能说的秘密[在线下载]第三方命令行工具[在线帮助]VBScript / JScript 在线参考
返回列表 发帖
测试系统变量:
  1. @echo off&setlocal enabledelayedexpansion
  2. for /l %%a in (1,1,100) do set "d=!d!&echo d"
  3. call :lp os
  4. call :lp os a setlocal endlocal
  5. call :lp os
  6. del /q db&pause
  7. goto :eof
  8. :lp
  9. %3
  10. if "%2" neq "" set "%1=%2"
  11. (echo d2cl2
  12. echo q
  13. echo,
  14. )>db
  15. (for /f "skip=1 tokens=2,3" %%a in ('debug^<db') do (
  16.      echo d%%b%%a:0000%d%&echo q&echo,
  17. ))>tem
  18. del /q db&ren tem db
  19. for /f "delims=" %%a in ('debug^<db^|findstr /i "%1="') do echo %%a
  20. echo,
  21. %4
复制代码
  1. 0DBD:03F0  52 4F 43 45 53 53 4F 52-53 3D 32 00 4F 53 3D 57   ROCESSORS=2.OS=W
  2. 0DBD:03F0  52 4F 43 45 53 53 4F 52-53 3D 32 00 4F 53 3D 61   ROCESSORS=2.OS=a
  3. 0DBD:03F0  52 4F 43 45 53 53 4F 52-53 3D 32 00 4F 53 3D 57   ROCESSORS=2.OS=W
  4. Press any key to continue . . .
复制代码
系统变量os在setlcoal-enlocal中去哪里了?,假如将os改成path,运行结果如下:
  1. 0DBD:0400  69 6E 64 6F 77 73 5F 4E-54 00 50 41 54 48 3D 43   indows_NT.PATH=C
  2. 'debug' is not recognized as an internal or external command,
  3. operable program or batch file.
  4. 'debug' is not recognized as an internal or external command,
  5. operable program or batch file.
  6. 0DBD:0400  69 6E 64 6F 77 73 5F 4E-54 00 50 41 54 48 3D 43   indows_NT.PATH=C
  7. Press any key to continue . . .
复制代码
在重新设定path后,debug命令变得无效。
***共同提高***

TOP

本帖最后由 batman 于 2011-4-23 13:44 编辑

还是测试说明问题,但也带来了新问题。。。。
代码:
  1. @echo off&setlocal enabledelayedexpansion
  2. for /l %%a in (1,1,100) do set "d=!d!&echo d"
  3. call :lp _str a
  4. call :lp _str b setlocal endlocal
  5. call :lp _str s
  6. del /q db&pause
  7. goto :eof
  8. :lp
  9. %3
  10. if "%2" neq "s" set "%1=%2"
  11. (echo d2cl2
  12. echo q
  13. echo,
  14. )>db
  15. (for /f "skip=1 tokens=2,3" %%a in ('debug^<db') do (
  16.      echo d%%b%%a:0000%d%&echo q&echo,
  17. ))>tem
  18. del /q db&ren tem db
  19. for /f "delims=" %%a in ('debug^<db^|findstr /i "%1="') do echo %%a
  20. echo,
  21. %4
复制代码
结果:
  1. 0DBD:0640  5F 53 54 52 3D 61 00 42-4C 41 53 54 45 52 3D 41   _STR=a.BLASTER=A
  2. 0DBD:0640  5F 53 54 52 3D 62 00 42-4C 41 53 54 45 52 3D 41   _STR=b.BLASTER=A
  3. 0DBD:0640  5F 53 54 52 3D 61 00 42-4C 41 53 54 45 52 3D 41   _STR=a.BLASTER=A
  4. Press any key to continue . . .
复制代码
上面的测试表明,setlocal前以及setlcoal-endlocal中以及endlocal后_str变量在内存中储存的地址没有改变(至少是开始值没有改变)。同时说明了cmd中为什么变量名不分大小写,因为不管变量中的字符是不是大小写,内存中统一是以大写的字符储存的变量。但这里又有一个问题了,既然内存中只会储存一个名为_str的变量,那么endlocal后这个变量的值又是怎么恢复为前面的值的,难道还有一个临时储存变量的地方?
***共同提高***

TOP

本帖最后由 cjiabing 于 2011-4-23 13:15 编辑
80# batman


1,用来说明微软为什么使用全字符ANSI来排列变量名。
2,命令解释器进内存中的环境变量区间是如何匹配的,是拿着变量名一个一个的遍历所有变量名来比较,还是按着ANSI顺序逐字比较变量名。
hanyeguxing 发表于 2011-4-23 10:20

      还是兄科学发展观学得好,不懂他们鼓捣出什么“真理”出来没有!~
      既然是“变量机制”,至少得出个有现实意义的结论,好指导我们平时怎么设置变量。
      比如用 !var! 还是用 %var% ,用不同的变量还是用同一个变量,用%abc% 顺序的,还是%zijizuodepichulibianliangjizhi%冗长颠倒的变量,用变量还是用临时文件,用多个不同变量,还是用同一个变量……
      再问深一点的:变量是怎么来的?它的作用是什么?它的运行机制是什么?它在内存中是怎么样工作的?变量是如何赋值和如何取消的?微软是怎么解释的?微软是怎么使用变量的?变量与什么有关?变量的极限是什么?有没有最佳和最差变量?有没有系统内部通用变量?怎么区分和联系各种变量?批处理的变量是否可以超出cmd.exe?计算机编码和进制对变量有什么影响?变量在解释器中如何解释?……
寂寞是黑白的,但黑白不是寂寞,是永恒。BAT 需要的不是可能,而是智慧。

TOP

人呢人呢?
这种版主级的舌战正是我所乐见的,向往了这么久,难得碰到一两次,怎么才讨论了一晚上+一上午就停火了...
问题还没解决呐...疑点还很多,举几个例子:
一、究竟是一张表还是N张表?子疑点:
1、系统变量与用户变量的关系,当用户变量覆盖系统变量时,系统变量去哪了?
2、setlocal后的变量是否和setlocal前的变量放在一张表里,并且一起按ansi排序呢?
二、变量存储时是否区分数据类型?
三、只感觉还有些问题迷迷糊糊,但没能抓住思绪,因此下文待续...

TOP

89# applba


批处理存储在内存的变量是否有数据类型之分呢?这又是一个分歧点,有得闹了

TOP

8# plp626


当然了,set /a 要把字符串类型转换成数字类型。这里是快了,如果后面的这个变量要参与数学计算的话,通过set设置的字符串还是需要再次转换成数字类型的,这样时间就扯平了。变量一般只设置一次,但是这个变量可能参与多次数学计算的话,很明显set /a  设置的数字类型将更有优势。

TOP

本帖最后由 batman 于 2011-4-23 11:21 编辑

再次测试(测试前猜想变量减少时,变量的内存存储开始地址不会改变)
代码:
  1. @echo off&setlocal enabledelayedexpansion
  2. del /q db-*.txt
  3. call :lp 1 100 random
  4. call :lp 10 20
  5. del /q db
  6. goto :eof
  7. :lp
  8. for /l %%a in (%1,1,%2) do set "_%%a=!%3!"
  9. (echo d2cl2
  10. echo q
  11. echo,
  12. )>db
  13. (for /f "skip=1 tokens=2,3" %%a in ('debug^<db') do (
  14.      echo d%%b%%a:0380&echo q&echo,
  15. ))>tem
  16. del /q db&ren tem db
  17. debug<db>db-%1.txt
  18. start db-%1.txt
复制代码
db-1.txt
  1. -d0DCC:0380
  2. 0DCC:0380  00 5F 31 3D 31 34 37 36-32 00 5F 31 30 3D 35 35   ._1=14762._10=55
  3. 0DCC:0390  37 37 00 5F 31 30 30 3D-32 31 31 35 33 00 5F 31   77._100=21153._1
  4. 0DCC:03A0  31 3D 37 37 35 35 00 5F-31 32 3D 31 35 35 38 36   1=7755._12=15586
  5. 0DCC:03B0  00 5F 31 33 3D 31 30 38-31 00 5F 31 34 3D 38 38   ._13=1081._14=88
  6. 0DCC:03C0  34 39 00 5F 31 35 3D 34-34 35 31 00 5F 31 36 3D   49._15=4451._16=
  7. 0DCC:03D0  31 32 39 34 35 00 5F 31-37 3D 32 35 37 33 35 00   12945._17=25735.
  8. 0DCC:03E0  5F 31 38 3D 31 33 30 31-31 00 5F 31 39 3D 32 37   _18=13011._19=27
  9. 0DCC:03F0  39 39 35 00 5F 32 3D 31-37 31 31 33 00 5F 32 30   995._2=17113._20
  10. -q
复制代码
db-10.txt
  1. -d0DCC:0380
  2. 0DCC:0380  00 5F 31 3D 31 34 37 36-32 00 5F 31 30 30 3D 32   ._1=14762._100=2
  3. 0DCC:0390  31 31 35 33 00 5F 32 3D-31 37 31 31 33 00 5F 32   1153._2=17113._2
  4. 0DCC:03A0  31 3D 32 37 37 36 30 00-5F 32 32 3D 33 37 36 35   1=27760._22=3765
  5. 0DCC:03B0  00 5F 32 33 3D 31 33 30-37 35 00 5F 32 34 3D 37   ._23=13075._24=7
  6. 0DCC:03C0  35 38 38 00 5F 32 35 3D-31 31 31 30 36 00 5F 32   588._25=11106._2
  7. 0DCC:03D0  36 3D 32 33 36 38 35 00-5F 32 37 3D 31 32 37 38   6=23685._27=1278
  8. 0DCC:03E0  39 00 5F 32 38 3D 32 30-33 30 31 00 5F 32 39 3D   9._28=20301._29=
  9. 0DCC:03F0  32 31 39 35 31 00 5F 33-3D 31 35 32 32 00 5F 33   21951._3=1522._3
  10. -q
复制代码
可见当变量减少时(部分变量被清空),其实就是对已有变量进行读取操作时,内存确实不会重新洗牌。
***共同提高***

TOP

本帖最后由 batman 于 2011-4-23 11:19 编辑

加入debug的测试
代码:
  1. @echo off&setlocal enabledelayedexpansion
  2. call :lp 1 10 random
  3. call :lp 11 100 random
  4. del /q db
  5. goto :eof
  6. :lp
  7. for /l %%a in (%1,1,%2) do set "_%%a=!%3!"
  8. (echo d2cl2
  9. echo q
  10. echo,
  11. )>db
  12. (for /f "skip=1 tokens=2,3" %%a in ('debug^<db') do (
  13.      echo d%%b%%a:0380&echo q&echo,
  14. ))>tem
  15. del /q db&ren tem db
  16. debug<db>%1.txt
  17. start %1.txt
复制代码
1.txt
  1. -d0D96:0380
  2. 0D96:0380  00 5F 31 3D 36 31 33 35-00 5F 31 30 3D 32 38 36   ._1=6135._10=286
  3. 0D96:0390  31 32 00 5F 32 3D 32 39-36 38 30 00 5F 33 3D 32   12._2=29680._3=2
  4. 0D96:03A0  33 30 36 39 00 5F 34 3D-33 31 32 32 37 00 5F 35   3069._4=31227._5
  5. 0D96:03B0  3D 38 34 37 37 00 5F 36-3D 32 33 39 38 38 00 5F   =8477._6=23988._
  6. 0D96:03C0  37 3D 33 32 36 31 36 00-5F 38 3D 32 39 35 38 00   7=32616._8=2958.
  7. 0D96:03D0  5F 39 3D 32 37 37 32 31-00 42 4C 41 53 54 45 52   _9=27721.BLASTER
  8. 0D96:03E0  3D 41 32 32 30 20 49 35-20 44 31 20 50 33 33 30   =A220 I5 D1 P330
  9. 0D96:03F0  20 54 33 00 00 01 00 43-3A 5C 57 49 4E 44 4F 57    T3....C:\WINDOW
  10. -q
复制代码
11.txt
  1. -d0E0D:0380
  2. 0E0D:0380  00 5F 31 3D 36 31 33 35-00 5F 31 30 3D 32 38 36   ._1=6135._10=286
  3. 0E0D:0390  31 32 00 5F 31 30 30 3D-31 34 36 31 34 00 5F 31   12._100=14614._1
  4. 0E0D:03A0  31 3D 35 33 30 37 00 5F-31 32 3D 33 30 32 38 37   1=5307._12=30287
  5. 0E0D:03B0  00 5F 31 33 3D 31 30 35-31 00 5F 31 34 3D 35 39   ._13=1051._14=59
  6. 0E0D:03C0  36 37 00 5F 31 35 3D 32-37 34 37 38 00 5F 31 36   67._15=27478._16
  7. 0E0D:03D0  3D 31 35 33 37 33 00 5F-31 37 3D 31 37 30 31 33   =15373._17=17013
  8. 0E0D:03E0  00 5F 31 38 3D 32 36 38-31 37 00 5F 31 39 3D 38   ._18=26817._19=8
  9. 0E0D:03F0  31 33 31 00 5F 32 3D 32-39 36 38 30 00 5F 32 30   131._2=29680._20
  10. -q
复制代码
由此可见cmd在变量有变化的情况下会重新分配内存的储存地址,1.txt和11.txt中开始的地址分别为0D96:0380和0E0D:0380,而这一存储过程是按变量名+=号+值的全字符(实际上就是变量名,因为cmd是不会允许有同名变量的存在的)的ansi序列先后进行的。
***共同提高***

TOP

80# batman


1,用来说明微软为什么使用全字符ANSI来排列变量名。
2,命令解释器进内存中的环境变量区间是如何匹配的,是拿着变量名一个一个的遍历所有变量名来比较,还是按着ANSI顺序逐字比较变量名。
寒夜孤星:在没有说明的情况下,本人所有代码均运行在 XP SP3 下 (有问题请发贴,QQ临时会话已关闭)

TOP

有一个结论对指导我们提高效率还有一定意义的:

垃圾变量名集合包含待赋值变量名时,待赋值变量的赋值耗时
明显少于
垃圾变量名集合不包含待赋值变量名时,对 待赋值变量的赋值耗时

TOP

果然是 变量名+值 都一起以字符存储的。
难怪 set a=1 比 set /a a=1要快。

这种存储法,自由度不错,某种程度上方便了用户,但效率就低了。

TOP

77# zm900612


从当年MS-DOS开始,这里就标记环境变量的段地址值,到windows下都没变过。。。
寒夜孤星:在没有说明的情况下,本人所有代码均运行在 XP SP3 下 (有问题请发贴,QQ临时会话已关闭)

TOP

hanyeguxing的debug变量储存展示已经力证了变量存储是按照变量名+=号+值全字符的ansi序列先后进行的,为什么还要强调变量的读取又不是按照这一基本序列机制呢?
***共同提高***

TOP

hanyeguxing的debug变量储存展示已经力证了变量存储是按照变量名+=号+值全字符的ansi序列先后进行的,为什么还要强调变量的读取又不是按照这一基本序列机制呢?
***共同提高***

TOP

从内存中可以看出,几乎和set 显示的一样,唯一的差别就是%COMSPEC%永远在内存的最前面。。。
寒夜孤星:在没有说明的情况下,本人所有代码均运行在 XP SP3 下 (有问题请发贴,QQ临时会话已关闭)

TOP

返回列表