<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Windows on 我的博客</title><link>https://diankao.github.io/tags/windows/</link><description>Recent content in Windows on 我的博客</description><generator>Hugo</generator><language>zh-cn</language><lastBuildDate>Tue, 01 Sep 2026 10:27:17 +0800</lastBuildDate><atom:link href="https://diankao.github.io/tags/windows/index.xml" rel="self" type="application/rss+xml"/><item><title>删不掉的 nul：AI 编程助手在 Windows 上的一次跨平台口误</title><link>https://diankao.github.io/posts/nul-ghost-file/</link><pubDate>Tue, 01 Sep 2026 10:27:17 +0800</pubDate><guid>https://diankao.github.io/posts/nul-ghost-file/</guid><description>&lt;p&gt;用 AI 编程助手（Claude Code、ZCode 这类 agent）在 Windows 上干活的人，迟早会在某个项目根目录捡到一个幽灵：一个 0 字节的文件，名字叫 &lt;code&gt;nul&lt;/code&gt;。&lt;code&gt;git status&lt;/code&gt; 里躺着个 &lt;code&gt;?? nul&lt;/code&gt;，资源管理器里看得见，右键删除却报&amp;quot;找不到该项目&amp;quot;。看得见，删不掉，标准的幽灵文件。&lt;/p&gt;
&lt;p&gt;它不是病毒，不是 bug，是 AI 助手的一句&lt;strong&gt;跨平台口误&lt;/strong&gt;。&lt;/p&gt;
&lt;h2 id="口误发生在哪一句"&gt;口误发生在哪一句&lt;/h2&gt;
&lt;p&gt;AI 助手在 Windows 上跑命令，走的通常是 Git Bash——一个 POSIX 语义的 shell。而模型执行命令时有个职业习惯：把无关的日志和报错重定向丢弃，保持输出干净。丢弃输出的写法在两个世界长得不一样：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Windows cmd： some.exe &amp;gt;nul （nul 是设备，输出进了黑洞）
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Bash： some.exe &amp;gt;/dev/null （/dev/null 是设备，输出进了黑洞）
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;模型识别到宿主是 Windows，出于好意切了 cmd 方言，写下 &lt;code&gt;&amp;gt;nul&lt;/code&gt;。但实际执行这句的 shell 是 Git Bash。在 Bash 眼里，&lt;code&gt;nul&lt;/code&gt; 不是设备，就是一个普通的文件名——重定向的目标文件不存在时 Bash 会怎么办？创建它。于是磁盘上多了这么个东西。&lt;/p&gt;
&lt;p&gt;一句字面级别的口误：&lt;strong&gt;语法是 cmd 的，解释器是 Bash 的&lt;/strong&gt;。两边单独看都没错，拼在一起就生成了一个不属于任何一方意图的文件。&lt;/p&gt;
&lt;h2 id="为什么看得见删不掉"&gt;为什么看得见、删不掉&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;nul&lt;/code&gt; 是 DOS 时代的设备保留名，同一家族还有 &lt;code&gt;con&lt;/code&gt;、&lt;code&gt;prn&lt;/code&gt;、&lt;code&gt;aux&lt;/code&gt;、&lt;code&gt;com1&lt;/code&gt; 到 &lt;code&gt;com9&lt;/code&gt;、&lt;code&gt;lpt1&lt;/code&gt; 到 &lt;code&gt;lpt9&lt;/code&gt;。Windows 的 Win32 层在解析路径时，会把出现在文件名位置上的这些名字&lt;strong&gt;别名到设备对象&lt;/strong&gt;上。所以资源管理器、&lt;code&gt;del nul&lt;/code&gt;、以及一切走 Win32 路径的程序，操作这个名字时碰到的其实是设备，不是文件——&amp;ldquo;找不到该项目&amp;quot;就是这么来的：它找的确实不是那个文件。&lt;/p&gt;</description></item><item><title>Qt Creator 底下那个“控制台”是假的：一次 Windows 中文乱码排查实录</title><link>https://diankao.github.io/posts/qtcreator-fake-console-encoding-trap/</link><pubDate>Mon, 17 Aug 2026 17:48:32 +0800</pubDate><guid>https://diankao.github.io/posts/qtcreator-fake-console-encoding-trap/</guid><description>&lt;p&gt;前段时间写 loghandler，需求说出来特别简单：console 里看的、调试输出里看的、实际落盘的内容，编码得一致。就这么点要求，被中文乱码折腾了好久。各种组合来回试过，才定位到元凶不是代码，而是观察工具本身：&lt;strong&gt;Qt Creator 底部那个长得像控制台的窗格，其实不是控制台，是 IDE 重定向、转述过的 output&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;先把结论放在最前面：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;那个窗格的大名是&amp;quot;应用程序输出&amp;quot;（Application Output）。Qt Creator 运行程序时不给它开控制台，而是用管道接住进程的 stdout/stderr，读出字节后&lt;strong&gt;由 IDE 自己解码&lt;/strong&gt;再显示。它是转述者，不是终端。&lt;/li&gt;
&lt;li&gt;所以 &lt;code&gt;SetConsoleOutputCP()&lt;/code&gt; 对它&lt;strong&gt;完全无效&lt;/strong&gt;——那是设置真控制台渲染解码的 API，而这条链路上压根没有&amp;quot;控制台渲染&amp;quot;这一环。&lt;/li&gt;
&lt;li&gt;printf 的字节流会被窗格按系统本地代码页（中文 Windows 即 GBK）固定解码。源文件是 UTF-8 的话，printf 直出中文在这个窗格里&lt;strong&gt;必乱&lt;/strong&gt;，怎么设置都救不回来。&lt;/li&gt;
&lt;li&gt;更迷惑的是 qDebug 走的是另一条 Unicode 通道，在窗格里&lt;strong&gt;永远正常&lt;/strong&gt;。&amp;ldquo;qDebug 好的、printf 坏的&amp;quot;这个组合，会把你引向一连串错误归因。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;以下实测基于 Qt 5 + Qt Creator（起码大版本 5 是这样）。只要 Creator 还是&amp;quot;管道重定向 + 自己解码&amp;quot;这个架构，这个坑就大概率还在；不同版本的解码细节可能变化，所以文末的验证方法比这里的结论更重要。&lt;/p&gt;
&lt;h2 id="症状qdebug-正常printf-乱码"&gt;症状：qDebug 正常，printf 乱码&lt;/h2&gt;
&lt;p&gt;程序里两种输出混用——qDebug 做调试，printf/fprintf 是老代码或第三方库。在 Qt Creator 里一跑：qDebug 的中文正常，printf 的中文全是 &lt;code&gt;涓枃娴嬭瘯&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;这类乱码不用背规律，看长相查表就能反推出&amp;quot;输的什么码、解的什么码&amp;rdquo;。GitHub 上这份 &lt;a href="https://github.com/justjavac/unicode-encoding-error-table"&gt;unicode-encoding-error-table&lt;/a&gt; 按外观特征收录了常见错法，&lt;code&gt;涓枃娴嬭瘯&lt;/code&gt; 这种&amp;quot;古文码&amp;quot;就是 UTF-8 字节被按 GBK 解读——3 字节的汉字被拆成 2+1 错配，长度都对不上，看起来自然乱得不像话。反过来说，看到它就知道：输出端发的是 UTF-8，解码端在用 GBK。&lt;/p&gt;</description></item></channel></rss>