C++ 在Mac上对带有汉字的命令调用popen()

C++ 在Mac上对带有汉字的命令调用popen(),c++,macos,encoding,popen,utf-16,C++,Macos,Encoding,Popen,Utf 16,我试图在Mac上使用popen()命令在文件上执行一个程序。为此,我创建了一个形式的命令,然后在此命令上调用popen()。现在,这两个组件都在char*中声明。我需要读取命令的输出,因此需要popen()给出的管道 现在,文件路径可以包含中文、日文、俄文和几乎任何其他字符。为此,我可以将文件的路径表示为wchar\u t*。但这对popen()不起作用,因为显然Mac/Linux没有像Windows那样的大开放空间 我还有别的办法可以让这一切顺利吗?我从一个只能给我wchar\u t*的数据结

我试图在Mac上使用popen()命令在文件上执行一个程序。为此,我创建了一个
形式的命令,然后在此命令上调用popen()。现在,这两个组件都在char*中声明。我需要读取命令的输出,因此需要popen()给出的管道

现在,文件路径可以包含中文、日文、俄文和几乎任何其他字符。为此,我可以将文件的路径表示为wchar\u t*。但这对popen()不起作用,因为显然Mac/Linux没有像Windows那样的大开放空间

我还有别的办法可以让这一切顺利吗?我从一个只能给我wchar\u t*的数据结构中获取文件的路径,因此我必须从那里获取它,并在需要时进行适当的转换

提前谢谢

编辑:

好像有一天你会把头发拔出来

因此,我尝试使用wcstombs,但对“C.UTF-8”及其任何排列的setlocale调用失败。毫不奇怪,wcstombs调用失败,之后返回-1

然后,我尝试根据在谷歌上搜索的一些示例代码编写自己的iconv实现。我想出了一个顽固地拒绝工作的办法:

iconv_t cd = iconv_open("UTF-8", "WCHAR_T");
// error checking here

wchar_t* inbuf = ...; // get wchar_t* here
char outbuf[<size-of-inbuf>*4+1];

size_t inlen  = <size-of-inbuf>;
size_t outlen = <size-of-inbuf>*4+1;

char* c_inbuf  = (char*) inbuf;
char* c_outbuf = outbuf;

int ret = iconv(cd, &c_inbuf, &inlen, &c_outbuf, &outlen);
// more error checking here
iconv_t cd=iconv_打开(“UTF-8”、“WCHAR_t”);
//在此处检查时出错
wchar_t*inbuf=…;//到这里来
煤焦突出[*4+1];
大小_t inlen=;
大小输出=*4+1;
char*c_inbuf=(char*)inbuf;
char*c_exputf=exputf;
int ret=iconv(cd、c_-inbuf、c_-inlen、c_-extuf和c_-outlen);
//这里有更多的错误检查
iconv始终返回-1,错误号设置为EINVAL。我已验证
设置是否正确。我不知道为什么这个代码现在失败了

编辑2:

iconv失败,因为我没有正确设置输入缓冲区长度。另外,Mac似乎不支持“WCHAR\u t”编码,所以我将其改为UTF-16。现在我已经更正了长度并更改了from编码,但iconv只是返回,没有转换任何字符。它只返回0

为了调试这个问题,我甚至将输入字符串更改为临时字符串,并适当地设置输入长度。即使这个iconv调用也只返回0。我的代码现在看起来像:

iconv_t cd = iconv_open("UTF-8", "UTF-16");
// error checking here

wchar_t* inbuf = ...; // get wchar_t* here - guaranteed to be UTF-16
char outbuf[<size-of-inbuf>*4+1];

size_t inlen  = <size-of-inbuf>;
size_t outlen = <size-of-inbuf>*4+1;

char* c_inbuf  = "abc"; // (char*) inbuf;
inlen = 4;
char* c_outbuf = outbuf;

int ret = iconv(cd, &c_inbuf, &inlen, &c_outbuf, &outlen);
// more error checking here
iconv_t cd=iconv_打开(“UTF-8”、“UTF-16”);
//在此处检查时出错
wchar_t*inbuf=…;//在此处获取wchar\u t*-保证为UTF-16
煤焦突出[*4+1];
大小_t inlen=;
大小输出=*4+1;
char*c_inbuf=“abc”//(char*)inbuf;
inlen=4;
char*c_exputf=exputf;
int ret=iconv(cd、c_-inbuf、c_-inlen、c_-extuf和c_-outlen);
//这里有更多的错误检查
我已确认转换器描述符已正确打开。源编码是正确的。输入缓冲区包含几个简单字符。所有内容都是硬编码的,iconv不转换任何字符,只返回0,EXPUFF仍然为空


精神错乱警报

对于
popen
,您需要一个UTF-8字符串。为此,您可以使用在不同编码之间进行转换,包括从本地
wchar\t
编码到UTF-8。(请注意,在我安装的Mac OS上,
wchar\u t
实际上是32位,而不是16位。)

编辑下面是一个在OS X Lion上工作的示例。我在使用
wchar\u t
编码时没有遇到任何问题(它记录在
iconv
手册页中)

#包括
#包括
#包括
#包括
#包括
char*utf8path(常量wchar\u t*wchar,大小utf32\u字节)
{
字符结果缓冲区[MAXPATHLEN];
iconv_t转换器=iconv_打开(“UTF-8”、“wchar_t”);
char*result=result\u缓冲区;
字符*输入=(字符*)wchar;
大小\u t输出\u可用\u大小=结果\u缓冲区的大小;
大小\u t输入\u可用\u大小=utf32\u字节;
大小\结果\代码=iconv(转换器、输入和输入\可用\大小、结果和输出\可用\大小);
如果(结果_代码==-1)
{
佩罗尔(“iconv”);
返回NULL;
}
iconv_关闭(转换器);
返回strdup(结果缓冲区);
}
int main()
{
wcharèt helloèu world[]=L“/è/path/to/hello/world.txt”;
char*utf8=utf8path(hello\u world,hello\u world的大小);
printf(“%s\n”,utf8);
免费(utf8);
返回0;
}

utf8\u hello\u world
函数接受具有字节长度的
wchar\u t
字符串,并返回等效的UTF-8字符串。如果处理指向
wchar\u t
的指针而不是
wchar\u t
的数组,则需要使用
(wcslen(ptr)+1)*sizeof(wchar\u t)
而不是
sizeof
popen
需要UTF-8字符串。为此,您可以使用在不同编码之间进行转换,包括从本地
wchar\t
编码到UTF-8。(请注意,在我安装的Mac OS上,
wchar\u t
实际上是32位,而不是16位。)

编辑下面是一个在OS X Lion上工作的示例。我在使用
wchar\u t
编码时没有遇到任何问题(它记录在
iconv
手册页中)

#包括
#包括
#包括
#包括
#包括
char*utf8path(常量wchar\u t*wchar,大小utf32\u字节)
{
字符结果缓冲区[MAXPATHLEN];
iconv_t转换器=iconv_打开(“UTF-8”、“wchar_t”);
char*result=result\u缓冲区;
字符*输入=(字符*)wchar;
大小\u t输出\u可用\u大小=结果\u缓冲区的大小;
大小\u t输入\u可用\u大小=utf32\u字节;
大小\结果\代码=iconv(转换器、输入和输入\可用\大小、结果和输出\可用\大小);
如果(结果_代码==-1)
{
佩罗尔(“iconv”);
返回NULL;
}
iconv_关闭(转换器);
返回strdup(结果缓冲区);
}
int main()
{
wcharèt helloèu world[]=L“/è/path/to/hello/world.txt”;
char*utf8=utf8path(hello\u world,hello\u world的大小);
printf(“%s\n”,utf8);
免费(utf8);
返回0;
}
utf
#include <sys/param.h>
#include <string.h>
#include <iconv.h>
#include <stdio.h>
#include <errno.h>

char* utf8path(const wchar_t* wchar, size_t utf32_bytes)
{
    char result_buffer[MAXPATHLEN];

    iconv_t converter = iconv_open("UTF-8", "wchar_t");

    char* result = result_buffer;
    char* input = (char*)wchar;
    size_t output_available_size = sizeof result_buffer;
    size_t input_available_size = utf32_bytes;
    size_t result_code = iconv(converter, &input, &input_available_size, &result, &output_available_size);
    if (result_code == -1)
    {
        perror("iconv");
        return NULL;
    }
    iconv_close(converter);

    return strdup(result_buffer);
}

int main()
{
    wchar_t hello_world[] = L"/éè/path/to/hello/world.txt";

    char* utf8 = utf8path(hello_world, sizeof hello_world);
    printf("%s\n", utf8);
    free(utf8);
    return 0;
}
// Do this once at program startup
setlocale(LC_ALL, "en_US.UTF-8");
...
// Error checking omitted for expository purposes
wchar_t *wideFilename = ...;  // This comes from wherever
char filename[256];  // Make sure this buffer is big enough!
wcstombs(filename, wideFilename, sizeof(filename));
// Construct popen command using the UTF-8 filename