为什么 Windows 日文语言环境使子进程 getenv return 的值与 putenv 的值不同?

Why does Windows Japanese locale make child process getenv return different value than was put with putenv?

Windows system locale 是日语时,为什么子进程的 getenv 结果与父进程的 putenv 中使用的值不完全匹配?

如果我的变量值未使用有效字符,是否有一系列有效的十六进制值保证对所有 Windows 系统局部变量的环境变量有效?

当语言环境设置为 "English (United States)" 时,下面的示例程序显示了此行为:

$ ./test.exe 1
parent: expected 13, got 13
 child: expected 13, got 13

当系统区域设置为 "Japanese (Japan)" 时,相同的程序(未重新编译)显示不同的行为:

$ ./test.exe 1
parent: expected 13, got 13
 child: expected 13, got 45

前 5 个字符匹配,但第 6 个和第 7 个字符不匹配。


这是示例程序。我在取消选择 "Precompiled header"、取消选择 "Security Development Lifecycle checks"、选择 "Empty Project" 并将以下内容添加为 [=37] 时使用默认的 Visual Studio 2012 "Win32 Console Application" 新项目设置进行编译=] 在 "Source Files" 下。我是运行Windows7.

#include <cstdlib>
#include <iomanip>
#include <iostream>
#include <string>

int main(int argc, char* argv[])
{
    const int index_6_value = 0x13;
    std::string label = argc == 2 ? "parent" : " child";
    const char name[] = { 0x73 /*s*/, 0 };
    char* before_insert = getenv(name);
    if ( argc == 1 && before_insert != 0) std::cout << label << ": expected " << std::hex << index_6_value << ", got " << int(before_insert[6]) << std::endl;

    if (argc > 1)
    {
        //                                       0     1     2     3     4     5     6     7
        char put_arg[] = { 0x73/*s*/, 0x3D/*=*/, 0x49, 0x73, 0xb0, 0xf6, 0xe3, 0x87, 0x13, 0 };
        putenv(put_arg);
        char* after_insert = getenv(name);
        if (after_insert) std::cout << label << ": expected " << std::hex << index_6_value << ", got " << int(after_insert[6]) << std::endl;

        std::string command = std::string("\"") + argv[0] + "\"";
        std::system(command.c_str());
    }

    return 0;
}

putenv 变量值应限制为可打印的 ASCII 值,否则 Windows 可能无法正确保留值,具体取决于本地。这没有很好地记录,但这个想法可能是为了避免双字节局部变量中的无效多字节序列,你可以看到可打印的 ASCII 值(0x20-0x7E)在所有代码页:

https://msdn.microsoft.com/en-us/goglobal/bb964654

跨平台和跨本地环境变量使用来存储任意字节很难正确执行,应该避免。