繁体   English   中英

如何在OSX上通过vswprintf格式化宽字符串(想要返回std :: wstring)

[英]How to format wide char string via vswprintf on OSX (want to return std::wstring)

我需要实现一个函数来格式化宽字符串并返回std :: wstring。 我的实施是:

std::wstring format(const wchar_t* fmt, ...)
{
    std::wstring ret;

    va_list va;
    va_start(va, fmt);

    int size = vswprintf(nullptr, 0, fmt, va);
    if (size > 0)
    {
        ret.resize(size + 1);
        vswprintf(&ret[0], size + 1, fmt, va);
    }

    va_end(va);
    return ret;
}

它在Windows上运行良好,但不幸的是它在osx上不起作用,因为vswprintf(nullptr,0,fmt,va)将返回-1。

只能使用std,我不能假设字符串长度在一定范围内。

我认为应该有一些方法可以做到这一点,但我找不到,你能帮忙吗? 谢谢

似乎Darwin版本实际上是根据vfwprintf的规范vfwprintf 不幸的是,似乎没有方便的方法来计算格式字符串的长度,就像使用常规单字节字符串一样(通过传递NULL目标字符串)。

经过大量研究后,我发现似乎有两种可行的解决方案,这两种解决方案都在这个答案中提到:

我不喜欢迭代分配方法,因为在分配足够多的情况下盲目地尝试相同的操作似乎是低效的。

我首选的解决方案是首先将字符串(一次!)格式化为/dev/null以计算长度,然后使用它来调整缓冲区的大小。 有必要复制变量args列表来执行此操作,因为它由vs *函数使用。 这最接近你如何做它,只是使用空流而不是空字符串。

我建议的解决方案是:

std::wstring format(const wchar_t* fmt, ...)
{
    std::wstring ret;

    va_list va;
    va_start(va, fmt);

    va_list vc;
    va_copy(vc, va);

    FILE* fp = fopen("/dev/null", "w");
    int size = vfwprintf(fp, fmt, vc);
    fclose(fp);

    if (size > 0)
    {
        ret.resize(size + 1);
        vswprintf(&ret[0], size + 1, fmt, va);
    }

    va_end(va);
    va_end(vc);

    return ret;
}

我在Mac OS X上用以下代码测试了这个,并观察了预期的输出:

int main(int argc, char* argv[])
{
    auto outstr = format(L"Hello %ls, you are %u years old.\n", L"Fred", 65);

    std::wcout << outstr << std::endl;

    return 0;
}

伪代码:

buffer.resize(1)
loop:
    res = vswprintf(buffer, args)
    if res indicates success:
        break
    buffer.resize(buffer.size() * 2)
buffer.truncate()

换句话说,您只需尝试增加缓冲区大小,直到成功为止。 我会从大于1个字符的东西开始,基本上这样大多数电话都不必重复,但这只是性能微调。

一种可能的解决方案可能是使用C11标准函数vswprintf_s函数。 这不是完全可移植的,因为C11使得它可以实现这个功能,但我提到它以防你的实现实现它。

C ++ 14仅指定C99标准库,此函数在C11中。 但是,如果您的C ++编译器的相关C编译器支持C11,那么它可能会使该函数直接从C ++中获得。 即使它没有,你可以将该代码包装在C函数中并从C ++调用该C函数。

vswprintf_s函数使用不同的参数来vswprintf所以仔细检查其文档。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM