c++ - 如何使用 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
*/
解决方案
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 来执行此操作。
推荐阅读
- ruby - Ruby中调用Struct对象的.to_a时数组元素的顺序
- amazon-web-services - 在 CodeBuild 阶段运行 kubectl apply -f hello-k8s.yml 时出现“无法识别“hello-k8s.yml”:未授权”错误
- c# - 防止列表框选择
- c# - 从仪表板 (/Template/Index) 重定向到 Login.cshtml 视图后显示的旧验证消息
- c# - 如何在 Azure 管道中的多个作业之间共享构建的 .NET Core 项目?
- stm32 - STM32写入EEPROM(I2C)/通过I2C生成数据失败与寄存器
- chunked-encoding - 使用 Tsung 发送分块请求
- r - 使用 R 抓取 SoFifa.com 时为玩家的国籍选择什么 css 元素?
- go - GRPC中错误响应的正确方法?
- python - 如何使用 ansible playbook 在 python 中运行 Ansible 模块