
[討論]cmd究竟是基于Ansi還是Unicode的最后由 CrLf 于 -10-24 20:25閑聊時好幾次聽寒夜版主說過,cmd 內部是以 Unicode 編碼來“暗箱操作”的,但是一直在腹誹這到底是推論還是猜測...不過到至今也沒有找到有力的反例,倒是收集了幾個間接支持該論點的證據(jù):【1,在 for 中,參數(shù)變量名以 Unicode 排列】這是 plp626 在某個關于 for 參數(shù)的討論帖中給出的示范代碼:
- :: cmd命令行下粘貼如下代碼
- :: 老 到 耣 的unicode編碼(連續(xù)地)為 8001 到 8023
- set ss=1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
- for /f tokens=1-31 %老 in (%ss%)do @echo %老 %耂 %考 %耄 %者 %耆 %耇 %耈 %耉 %耊 %耋 %而 %耍 %耎 %耏 %耐 %耑 %耒 %耓 %耔 %耕 %耖 %耗 %耘 %耙 %耚 %耛 %耜 %耝 %耞 %耟 %耠 %耡 %耢 %耣
nclick="copycode($('code0'));">復制代碼
很有意思,將 老~耣 這 23 個字分別保存為 Ansi 與 Unicode 格式,可以看到 Ansi 編碼中這些字的十六進制是無序的排列,而 Unicode 編碼中則是順序排列的,這說明至少在 for 命令中,參數(shù)變量名是以 Unicode 編碼順序排序。【2,個人猜測,變量有可能是以 Unicode 存儲】第二個證據(jù)要說的還是 plp 的帖子,不過是關于 chcp 切分字符的另一帖,該貼的核心內容是通過 chcp 437 切換到英文代碼頁,可以使原本不可分的寬字節(jié)可以被拆分為兩個字符存儲和輸出。有意思的是,chcp 之前的寬字節(jié)不受影響,已經存儲在變量中的寬字節(jié)是不會被拆分的。我一直無法理解,就算能把寬字節(jié)拆開,又如何在存儲時告訴 cmd 這兩個字節(jié)不是一組的呢?雖然 chcp 時字節(jié)會按照 nls 表發(fā)生變化,但我們知道 Ansi(其實是 GBK)中的寬字節(jié)由 0
x80~0
xff 范圍內的字符組成,如何讓 cmd 區(qū)別對待誰是寬字符、誰是單字節(jié)字符、誰又是被拆分成兩個字符的寬字符呢?舉個例子,比如騷包這個兩個字同時出現(xiàn)的時候,就一定是“騷包”的意思嗎?我要是造個句子“離騷包含屈原晚年的苦悶與矛盾”你該如何解讀呢?寬字節(jié)就像語言中的固定用詞,平時一組一組出現(xiàn),但是特殊情況下,“騷包”不一定是騷包,他也可能是騷和包,你又怎么知道它是騷包還是騷和包呢...我曾經揣測了好幾種可能,比如在相鄰字符之間安置分隔符,或者為不同代碼頁安排不同的變量表,但是前者無法解釋 cmd 用什么符號來作為分隔符,因為除 00 是變量與變量之間的分隔符外,所有符號都能被保存為變量內容,那就沒有符號能夠用來作為字符之間的分隔符了。而第二個猜測則是在寒夜用 debug 查看變量表時不攻自破,因為同一時間段能觀察到的活動的變量表唯一。現(xiàn)在回想起來,似乎還有另一種可能,cmd 保存變量時或許是用 Unicode 編碼存儲的,因為在 Unicode 編碼中所有字符都是雙字節(jié)的,這就能解釋 cmd 是如何區(qū)別對待寬字符、單字節(jié)字符、被拆分成兩個字符的寬字符了——因為它們保存到變量時都是被統(tǒng)一轉換為雙字節(jié),比如“騷”“包”被轉換成“ 騷”“ 包”,而“騷包”依然是“騷包”,這樣也就不存在被拆分的寬字符在變量中又合并的問題了。我做了個實驗,先在一個批處理中賦值了 8192*500 個幾乎全是漢字的字符串,又在另一個批處理中賦值了 8192*500 個全是數(shù)字的字符串,觀察二者內存占用都在 19 兆出頭,相差僅 200k,假如 cmd 是以 ansi 編碼存儲變量,那數(shù)字占用的內存應該只有漢字的一半,Unicode 格式的字節(jié)數(shù)則始終是字符數(shù)的兩倍(控制字符除外),所以這也能間接證明 cmd 有可能是以 Unicode 編碼保存變量的。我原以為此猜測有一個致命漏洞,就是變量內容中是不允許存在 00 的,但是 Unicode 編碼必然無法避免 00 的存在,這不是自相矛盾嗎?不過寒夜版主提醒我 Unicode 中的 00 是以 00 00 的形式成對存在的,所以就不擔心變量內容中的 00 導致變量被錯誤分割的問題了。【3、cmd /u 拒絕為外部命令提供 Ansi 轉 Unicode 服務?】我們知道 cmd /u 能輸出 Unicode 格式的文本,這種輸出不贈送文件頭,所以一般只用于附加輸出到已有文件頭的文件。但是有個有趣的現(xiàn)象,當我們使用 cmd /u /c 大部分外部命令 時是得不到 Unicode 格式輸出的,而所有的內部命令以及少部分“原本就能將結果以 Unicode 格式輸出”的外部命令(如 wmic、robocopy)則能夠通過 cmd /u 輸出為 Unicode 文本。這是否說明,其實 cmd /u 并不是將 Ansi 輸出轉化為 Unicode 編碼,而是 cmd 內部本來就是以 Unicode 進行操作,不使用 /u 開關時將轉換為 Ansi 再輸出,當我們使用了 cmd /u 時,cmd 只是不作為而已?以上三條證據(jù)擺在一起,是否在暗示著 cmd 私底下好像還真挺有可能是用 Unicode 來干活的?