删不掉的 nul:AI 编程助手在 Windows 上的一次跨平台口误

用 AI 编程助手(Claude Code、ZCode 这类 agent)在 Windows 上干活的人,迟早会在某个项目根目录捡到一个幽灵:一个 0 字节的文件,名字叫 nul。git status 里躺着个 ?? nul,资源管理器里看得见,右键删除却报"找不到该项目"。看得见,删不掉,标准的幽灵文件。 它不是病毒,不是 bug,是 AI 助手的一句跨平台口误。 口误发生在哪一句 AI 助手在 Windows 上跑命令,走的通常是 Git Bash——一个 POSIX 语义的 shell。而模型执行命令时有个职业习惯:把无关的日志和报错重定向丢弃,保持输出干净。丢弃输出的写法在两个世界长得不一样: Windows cmd: some.exe >nul (nul 是设备,输出进了黑洞) Bash: some.exe >/dev/null (/dev/null 是设备,输出进了黑洞) 模型识别到宿主是 Windows,出于好意切了 cmd 方言,写下 >nul。但实际执行这句的 shell 是 Git Bash。在 Bash 眼里,nul 不是设备,就是一个普通的文件名——重定向的目标文件不存在时 Bash 会怎么办?创建它。于是磁盘上多了这么个东西。 一句字面级别的口误:语法是 cmd 的,解释器是 Bash 的。两边单独看都没错,拼在一起就生成了一个不属于任何一方意图的文件。 为什么看得见、删不掉 nul 是 DOS 时代的设备保留名,同一家族还有 con、prn、aux、com1 到 com9、lpt1 到 lpt9。Windows 的 Win32 层在解析路径时,会把出现在文件名位置上的这些名字别名到设备对象上。所以资源管理器、del nul、以及一切走 Win32 路径的程序,操作这个名字时碰到的其实是设备,不是文件——“找不到该项目"就是这么来的:它找的确实不是那个文件。 ...

2026年9月1日 · 1 min

Qt Creator 底下那个“控制台”是假的:一次 Windows 中文乱码排查实录

前段时间写 loghandler,需求说出来特别简单:console 里看的、调试输出里看的、实际落盘的内容,编码得一致。就这么点要求,被中文乱码折腾了好久。各种组合来回试过,才定位到元凶不是代码,而是观察工具本身:Qt Creator 底部那个长得像控制台的窗格,其实不是控制台,是 IDE 重定向、转述过的 output。 先把结论放在最前面: 那个窗格的大名是"应用程序输出"(Application Output)。Qt Creator 运行程序时不给它开控制台,而是用管道接住进程的 stdout/stderr,读出字节后由 IDE 自己解码再显示。它是转述者,不是终端。 所以 SetConsoleOutputCP() 对它完全无效——那是设置真控制台渲染解码的 API,而这条链路上压根没有"控制台渲染"这一环。 printf 的字节流会被窗格按系统本地代码页(中文 Windows 即 GBK)固定解码。源文件是 UTF-8 的话,printf 直出中文在这个窗格里必乱,怎么设置都救不回来。 更迷惑的是 qDebug 走的是另一条 Unicode 通道,在窗格里永远正常。“qDebug 好的、printf 坏的"这个组合,会把你引向一连串错误归因。 以下实测基于 Qt 5 + Qt Creator(起码大版本 5 是这样)。只要 Creator 还是"管道重定向 + 自己解码"这个架构,这个坑就大概率还在;不同版本的解码细节可能变化,所以文末的验证方法比这里的结论更重要。 症状:qDebug 正常,printf 乱码 程序里两种输出混用——qDebug 做调试,printf/fprintf 是老代码或第三方库。在 Qt Creator 里一跑:qDebug 的中文正常,printf 的中文全是 涓枃娴嬭瘯。 这类乱码不用背规律,看长相查表就能反推出"输的什么码、解的什么码”。GitHub 上这份 unicode-encoding-error-table 按外观特征收录了常见错法,涓枃娴嬭瘯 这种"古文码"就是 UTF-8 字节被按 GBK 解读——3 字节的汉字被拆成 2+1 错配,长度都对不上,看起来自然乱得不像话。反过来说,看到它就知道:输出端发的是 UTF-8,解码端在用 GBK。 ...

2026年8月17日 · 2 min