【问题标题】:_vscwprintf on Mac OS X/LinuxMac OS X/Linux 上的 _vscwprintf
【发布时间】:2013-04-27 10:06:15
【问题描述】:

我正在为 Windows 编写的 Mac OS X 上移植一个应用程序。

在这个应用程序中,有很多 _vscwprintf 和 _vscprintf 的实例。

这个question 帮助我在 Mac OS X 上实现了 _vsprintf。但是 _vswprintf 的相同技术不起作用。

任何人都可以在 Mac OS X 上提供 _vscwprintf 的替代方案吗?或者有什么等效的方法吗?

【问题讨论】:

标签: c++ c linux macos


【解决方案1】:

Microsoft 将函数描述为返回格式化字符串时将使用的字符数 - 请注意,它们被记录为不包括空终止符。

int _vscprintf(
   const char *format,
   va_list argptr 
);
int _vscwprintf(
   const wchar_t *format,
   va_list argptr 
);

初步回答

因此,可以使用vsprintf()vswprintf() 模拟这些函数:

int _vscprintf(const char *format, va_list argptr)
{
    return(vsnprintf(0, 0, format, argptr));
}

int _vscwprintf(const wchar_t *format, va_list argptr)
{
    return(vswprintf(0, 0, format, argptr));
}

是否删除前导下划线取决于您;我会的。

请注意,上面的_vscwprintf() 实现是有缺陷的;请看下面的代码。


vscprintf()scprintf()

道歉:我写了vsprintf(),我需要写vsnprintf()(现在已在上面的代码中修复);但是,vswprintf() 已经有了更安全的缓冲区长度接口,所以没有vsnwprintf()。我更喜欢在发布代码之前(或之后不久)测试编译代码是有原因的——这几天没有足够的资金来做这件事令人厌烦。

这是vscprintf()(和scprintf())的SSCCE:

#include <stdio.h>
#include <stdarg.h>

extern int vscprintf(const char *format, va_list argptr);
extern int scprintf(const char *format, ...);

int vscprintf(const char *format, va_list argptr)
{
    return(vsnprintf(0, 0, format, argptr));
}

int scprintf(const char *format, ...)
{
    va_list args;
    va_start(args, format);
    int rc = vscprintf(format, args);
    va_end(args);
    return rc;
}

int main(void)
{
    int l = scprintf("%-8s %8d\n", "abc", 123);
    if (l > 0)
    {
        char buffer[l+1];
        int n = snprintf(buffer, sizeof(buffer), "%-8s %8d\n", "abc", 123);
        printf("%d = %d: %s", l, n, buffer);
    }
    return 0;
}

输出:

18 = 18: abc           123

vscwprintf()scwprintf()

结果证明_vscwprintf() 更难模拟,因为vswprintf() 函数不如vsnprintf() 函数有用。具体来说,vswprintf() 如果格式化的字符串不适合格式化的空间,则会报告错误,而vsnprintf() 会报告缓冲区中需要的字符数(如果它适合的话)。因此,您必须反复试验:

#include <stdio.h>
#include <stdarg.h>
#include <wchar.h>

extern int vscwprintf(const wchar_t *format, va_list argptr);
extern int scwprintf(const wchar_t *format, ...);

int vscwprintf(const wchar_t *format, va_list argptr)
{
    // Unlike vsnprintf(), vswprintf() does not tell you how many
    // characters would have been written if there was space enough in
    // the buffer - it just reports an error when there is not enough
    // space.  Assume a moderately large machine so kilobytes of wchar_t
    // on the stack is not a problem.
    int buf_size = 1024;
    while (buf_size < 1024 * 1024)
    {
        va_list args;
        va_copy(args, argptr);
        wchar_t buffer[buf_size];
        int fmt_size = vswprintf(buffer, sizeof(buffer)/sizeof(buffer[0]), format, args);
        if (fmt_size >= 0)
            return fmt_size;
        buf_size *= 2;
    }
    return -1;
}

int scwprintf(const wchar_t *format, ...)
{
    va_list args;
    va_start(args, format);
    int rc = vscwprintf(format, args);
    va_end(args);
    return rc;
}

int main(void)
{
    int l = scwprintf(L"%-8ls %8d\n", L"abc", 123);
    if (l > 0)
    {
        wchar_t buffer[l+1];
        int n = swprintf(buffer, sizeof(buffer)/sizeof(buffer[0]), L"%-8ls %8d\n", L"abc", 123);
        wprintf(L"%d = %d: %ls", l, n, buffer);
    }
    return 0;
}

运行时,会产生输出

18 = 18: abc           123

(和之前一样)。

在 Mac OS X 10.8.3 上使用 GCC 4.7.3 进行测试(它是在 Mac OS X 10.7.5 上构建的,但这不会导致任何问题)。

【讨论】:

  • 感谢您的回答。但问题在于它对我不起作用。我以下列方式使用它: va_list copyarg; // 参数的副本。国际化; // 返回值。 va_copy(copyarg, argptr); len = vswprintf(NULL, 0, pFormat, copyarg); va_end(copyarg);返回 len;我做对了吗?其中有什么问题? len 的值(返回值)为 -1。
  • 我忘了你需要复制调用代码中的va_list; Microsoft 页面没有明确说明,但是如果您调用 v*printf() 函数,则 va_list 会被调用用完。您显示的内容应该有效(va_copy() 类似于 strcpy() 分配顺序 - 目标第一,源第二);我展示的也应该有效。我暂时无法轻松访问具有编译器(不要问!)的机器,所以我无法使用 SSCCE 进行验证。
  • 对于 char *,我做了和你提到的一样的方法并且工作正常。但是,同样的方法不适用于 wchar_t * 字符串。请同时提供 wchar_t * 的解决方案。
  • @dbasic:我已经为宽字符串提供了答案,但您也可以阅读手册页。如果您不知道如何做到这一点,那么现在是您做的时候了。您可以在 opengroup.org/onlinepubs/9699919799/toc.htm 找到 C99(当然还有 POSIX 本身)中函数的 POSIX 描述。
  • _vscwprintf 替换不起作用,因为当要写入的字符串大于缓冲区大小时,vswprintf 返回 -1。 (相比之下,如果缓冲区足够大,vsnprintf 返回将写入的字符数。)不知道为什么会有差异。有人有 _vscwprintf 的替代品吗?
【解决方案2】:

我建议改用open_wmemstream。类似的东西:

#include <stdio.h>
#include <string>
#include <stdarg.h> 

using namespace std;

wstring wstring_format(const wchar_t* format, ...)
{
    wchar_t* buf;
    size_t size;
    FILE* stream = open_wmemstream(&buf, &size);

    va_list args;
    va_start(args, format);
    vfwprintf(stream, format, args);
    va_end(args);

    fclose(stream);
    wstring result(buf, buf + size);
    free(buf);

    return result;
}

【讨论】:

    猜你喜欢
    • 2012-04-18
    • 2015-08-11
    • 1970-01-01
    • 1970-01-01
    • 2013-05-04
    • 1970-01-01
    • 2011-08-24
    • 2012-08-09
    • 1970-01-01
    相关资源
    最近更新 更多