2

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

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

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

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

4

2 回答 2

6

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()这是(和)的SSCCE scprintf()

#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 上构建的,但这不会导致任何问题)。

于 2013-05-03T05:24:26.090 回答
1

我建议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;
}
于 2020-04-09T18:44:21.387 回答