[新手上路]批处理新手入门导读[视频教程]批处理基础视频教程[视频教程]VBS基础视频教程[批处理精品]批处理版照片整理器
[批处理精品]纯批处理备份&还原驱动[批处理精品]CMD命令50条不能说的秘密[在线下载]第三方命令行工具[在线帮助]VBScript / JScript 在线参考
返回列表 发帖
本帖最后由 hanyeguxing 于 2011-4-23 09:03 编辑

环境变量名是按字符逐字顺序排列的,例如2排在17的后面,下面两图是系统环境变量在内存中的存储
.


.
为什么要用 set /a 呢?set /a 能代表单纯的变量读写吗?使用 set a=%#10000% 这样的形式更合适吧?
测试代码:
  1. @echo off
  2. rem set n=10000 1 39999
  3. rem set n=39999 -1 10000
  4. echo %time%开始%n%
  5. for /l %%a in (%n%) do set #%%a=1
  6. echo %time%赋值完成
  7. for /l %%a in (%n%) do set a=%#10000%
  8. echo %time%第一批完成
  9. for /l %%a in (%n%) do set a=%#39999%
  10. echo %time%第二批完成
  11. pause
复制代码
第一次set n=39999 -1 10000倒序两个差距千分之1.3,第二次set n=10000 1 39999正序(没关第一个cmd)差距千分之2.17
.

.
怎么就没得出有那么大的差距呢?
.

.
命令解释器在读写变量时是按照变量名逐个顺序匹配的的。
1,变量名顺序,以上图本地化变量组为例。
2,特例。特殊情况也是存在的,例如变量 %COMSPEC% 就单独排在整个变量的最前面。这个破规则从MS-DOS时代就开始了,因为那个时候他是核心,到今天的系统依然作如此保留。
3,两个变量之间由 00 空字符分隔
4,逐字匹配。先以变量名的第一个字符在本地变量存储空间顺序匹配变量名的第一个字符;如果匹配到,则继续在以第一字符开头的区间内继续匹配第二个字符,如果没有就直接返回为空...以此类推,而不是遍历整个变量存储空间。
这样做的好处是大大加快变量的读写速度。
如果变量存储的顺序是按照赋值的先后排列的话,那么每次读取都需要完整遍历一次整个本地变量空间,那是很没效率的,微软也不会这么设计。
附件: 您需要登录才可以下载或查看附件。没有帐号?注册
1

评分人数

寒夜孤星:在没有说明的情况下,本人所有代码均运行在 XP SP3 下 (有问题请发贴,QQ临时会话已关闭)

TOP

奇怪,你们为什么就不用debug直接查询本地化变量在内存中的存储呢,很容易的事
寒夜孤星:在没有说明的情况下,本人所有代码均运行在 XP SP3 下 (有问题请发贴,QQ临时会话已关闭)

TOP

本帖最后由 hanyeguxing 于 2011-4-23 09:23 编辑

  系统每运行一次命令解释器都要生成一个256字节的内存块——程序段前缀PSP(Program Segment Prefix),它包含了一些比较重要的信息,如内存单元、矢量、命令行上键入的文件名、命令行本身(用户运行程序的命令行的拷贝)、各种保留缓冲器存储地点的信息。只要涉及环境,那些存储地点之一就会保存系统环境地址。

  打开命令解释器,运行 for /l %a in (1,1,100) do set "#%a=%a" ,设置这些变量,接着运行 DEBUG

  在DEBUG命令状态下查看环境,首先查看偏移量2C处的两个字节:

  -D2CL2
   0B2DA:0020  66 05

  数据66 05是在某系统上得到的计算机环境的段地址值(操作时应以实际显示数为准),把这两对数以相反的顺序,并在后面跟上偏移量0,就能在DEBUG命令上显示系统环境。

  -D0566:0

附件: 您需要登录才可以下载或查看附件。没有帐号?注册
1

评分人数

    • plp626: debug方法确实能反映本质。用代码的输出只是 ...技术 + 1
寒夜孤星:在没有说明的情况下,本人所有代码均运行在 XP SP3 下 (有问题请发贴,QQ临时会话已关闭)

TOP

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

TOP

77# zm900612


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

TOP

80# batman


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

TOP

本帖最后由 hanyeguxing 于 2011-4-24 06:18 编辑

运行批处理时,命令解释器就复制了系统环境变量进入本地,这些系统变量也就本地化了,而 set 的都是本地,所以用set 也只改变本地环境变量
打个比方,系统变量为其他位置的一个源文件,系统变量本地化就像为他在当前目录创建快捷方式,快捷方式可以随意访问源文件。
而 set 这些本地化的系统变量就相当于修改了快捷方式名称,如何修改都不会改变源文件的名称
寒夜孤星:在没有说明的情况下,本人所有代码均运行在 XP SP3 下 (有问题请发贴,QQ临时会话已关闭)

TOP

本帖最后由 hanyeguxing 于 2011-4-25 11:34 编辑

对于:setlocal-endlocal
每运行一次setlocal将当前位置(本地环境变量位置,也就是命令解释器PSP中2C、2D字节所标记的环境段地址)的环境变量复制到临时位置,并将新变量继续写到当前位置,变量就是这么继承的...
运行endlocal运行时就清除当前位置所有变量,并将对应临时位置的变量复制回来。
这样,无论set还是其他命令(setlocal-endlocal除外),读写的都是本地环境变量位置里的变量
.............................................以上个人观点,哪天有人发现错了,记得不要拍砖。。。
测试:
  1. @echo off
  2. for /l %%a in (0,1,4) do set #%%a=%%a
  3. setlocal enableDelayedExpansion
  4. for /l %%a in (5,1,9) do set #%%a=%%a
  5. set #
  6. pause
  7. endlocal
复制代码


注意,内存分析时,批处理停在 pause 这条命令上,即没有执行 endlocal 呢......
附件: 您需要登录才可以下载或查看附件。没有帐号?注册
寒夜孤星:在没有说明的情况下,本人所有代码均运行在 XP SP3 下 (有问题请发贴,QQ临时会话已关闭)

TOP

本帖最后由 hanyeguxing 于 2011-4-25 11:46 编辑

debug时,只能很容易看到当前环境变量,因为临时的那些位置并不记录在PSP中(所有命令只读写当前环境变量)。。。我们可以换个内存数据工具软件来看嘛
寒夜孤星:在没有说明的情况下,本人所有代码均运行在 XP SP3 下 (有问题请发贴,QQ临时会话已关闭)

TOP

返回列表