首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何在OSX上通过vswprintf格式化宽字符字符串(希望返回std::wstring)

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

Stack Overflow用户
提问于 2016-03-29 17:36:25
回答 3查看 772关注 0票数 3

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

代码语言:javascript
运行
复制
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,并且我不能假设字符串长度在某个范围内。

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

EN

回答 3

Stack Overflow用户

发布于 2016-03-29 18:57:04

看起来达尔文的版本实际上是在运行according to the specification for vfwprintf。不幸的是,似乎也没有方便的方法来计算宽格式字符串的长度,方法与计算常规单字节字符串的方式相同(通过传递NULL目标字符串)。

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

我不喜欢迭代分配方法,因为盲目地多次尝试相同的操作,直到您分配了足够的空间,似乎效率很低。

我更喜欢的解决方案是格式化字符串(一次!)设置为/dev/null,以便计算长度,然后使用它来调整缓冲区的大小。执行此操作需要复制变量args列表,因为它由vs*函数消耗。无论如何,这是最接近您所做的事情,只是使用空流而不是空字符串。

因此,我提出的解决方案是:

代码语言:javascript
运行
复制
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上用以下代码测试了这一点,并观察到了预期的输出:

代码语言:javascript
运行
复制
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;
}
票数 1
EN

Stack Overflow用户

发布于 2016-03-29 17:53:20

伪码:

代码语言:javascript
运行
复制
buffer.resize(1)
loop:
    res = vswprintf(buffer, args)
    if res indicates success:
        break
    buffer.resize(buffer.size() * 2)
buffer.truncate()

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

票数 0
EN

Stack Overflow用户

发布于 2016-03-30 08:28:38

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

C++14只指定了C99标准库,这个函数在C11中。但是,如果您的C++编译器关联的C编译器支持C11,那么很可能会从C++中直接使用该函数。即使不是这样,您也可以将该代码包装在一个C函数中,然后从C++调用该C函数。

vswprintf_s函数对vswprintf使用了不同的参数,因此请仔细查看其文档。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/36280521

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档