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

标签 c++ windows macos c++11

我需要实现一个函数来格式化宽字符字符串并返回 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 版本实际上表现良好 according to the specification for vfwprintf .不幸的是,似乎也没有方便的方法来计算 wide 格式字符串的长度,就像计算常规单字节字符串一样(通过传递 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;
}

关于c++ - 如何在 OSX 上通过 vswprintf 格式化宽字符字符串(想要返回 std::wstring),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36280521/

相关文章:

c++ - 奇怪的 mktime 行为 - 如果将返回值分配给变量则更改

c++ - 使用 boost.spirit.parser 时无法破译编译错误

java - 从图像中去除背景噪音,使 OCR 的文本更清晰

c++ - 在 Debug模式下查看变量的内容? (带断点的除外)

macos - Gradle exec commandLine无法按预期工作

C++优雅模板注入(inject)接口(interface)

windows - 修补程序 KB2731284 - 如何安装?

ios - OSX Xcode 无法从首选项-> 下载中下载其他 iOS 模拟器

macos - 未检测到已安装的 ffmpeg。无法转换音频(python 2.7,mac os x)

R - 如何使 Choose.dir() 使用像 Choose.files( ) 这样的 Windows 文件资源管理器