首页 > 解决方案 > 如何使用 C++ 中的系统函数执行具有多字节字符的命令

问题描述

我正在尝试执行以下操作:

string command = "executable.exe .\\テストプログラム\\filename.ext";
int retval = system(command.c_str());

调试后,我发现多字节字符无法识别并且以随机字符表示。

我也尝试过先将命令存储在批处理文件中,然后再执行批处理文件。

filesystem::path batFile = filesystem::path(".\batFile.bat");
string command = "executable.exe .\\テストプログラム\\filename.ext";
writeBatCmd(batFile, command);
int retval = system(batFile.string().c_str());

我的发现是多字节字符已正确存储在 .bat 文件中,但在执行时,仍然会发生与上述相同的情况。

在 cmd 中执行创建的 .bat 文件可以正确运行命令。

使用 CreateProcess 函数而不是系统函数不会改变行为。

我最初的猜测是需要将字符串转换为 c_str 是导致该行为的原因,但是将命令写入 .bat 文件然后执行 .bat 证明了这一点。

在此先感谢您的帮助!

编辑:

尝试过的解决方案:
解决方案1 ​​将语言环境设置为utf8,然后直接调用程序。执行程序的命令存储在 wstring 对象中。在 wstring 对象中硬编码多字节字符时,没有问题。例子:

wstring cmd = L"executable.exe .\\テストプログラム\\filename.ext";

当执行这样的事情时,从多字节字符开始到字符串末尾的字符被截断:

wstring cmd = L"executable.exe " + pathToFile + L"\\filename.ext";
// cmd value: "executable.exe .\"

解决方案2
我也尝试过使用 u16string 对象,当使用它时,命令存储正确。问题是我不能在它上面调用系统函数,因为它是u16string,有没有可以用于u16string的系统函数?或者有没有办法将 u16string 转换为 wstring 而不会更改多字节字符?

u16string cmd = u"executable.exe .\\テストプログラム\\filename.ext";
// cmd value: executable.exe .\テストプログラム\filename.ext

解决方案 3
我尝试将语言环境设置为 utf8,然后将命令存储在 .bat 文件中,然后执行 .bat 文件。执行后,命令会正确存储在 .bat 文件中。在调用 .bat 文件时,多字节字符不会被识别/显示为单字节字符。

setlocale(LC_ALL, "en_US.utf8");
filesystem::path batFile = filesystem::path(".\batFile.bat");
u16string cmd = u"executable.exe .\\テストプログラム\\filename.ext";
// cmd value: executable.exe .\テストプログラム\filename.ext
writeAsBat(batFile , cmd);
// batfile content: 
//executable.exe .\テストプログラム\filename.ext
//EXIT /B %ERRORLEVEL%
int retval = system(batFile.string().c_str());
/*
Output: 
in .bat file: executable.exe .\テストプログラム\filename.ext
on execution of .bat file: executable.exe .\チE¹トゅログラム\filename.ext
*/

标签: c++batch-file

解决方案


Windows 在内部对所有系统功能使用 UTF-16。

如果您调用 MBCS/ANSI 函数,则首先使用当前代码页将参数转换为 UTF-16,然后解释和执行。

如果您当前的代码页设置正确 - 并且 UTF-8 不是有效的代码页 - 那么这应该可以工作。您可能需要代码页 932。

但是,您确实应该在 Windows 上出于所有目的调用宽字符函数。

激活我的通灵调试能力,我猜你的 C++ 文件是 UTF-8 格式的。

自 2018 年 4 月更新以来,您现在可以将 UTF-8 设置为 C 中的当前字符集。 https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/setlocale-wsetlocale?view=msvc -160#utf-8-support

再开箱一点

可能发生的情况是,当您编译时,您的 C 字符串正在转换为字节序列,可能采用 UTF-8 编码。然后将这些字节写入批处理文件。但是批处理文件不能用 UTF-8编写,它们可以用当前代码页编写(无论如何,在您的情况下可能是日语代码页 932)。

解决您的问题

看起来您想编写一个批处理文件,因为您在调用程序时遇到了困难,并且已经找到了一个批处理文件作为解决方案。

如果是这种情况,您可能会更幸运地将 C 语言环境设置为 UTF-8,并直接调用程序,或者使用宽字符 API 来执行此操作。

https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/setlocale-wsetlocale?view=msvc-160#utf-8-support


推荐阅读