解决Visual C ++中缺少vwscanf的更好方法?

时间:2011-11-03 15:30:15

标签: c++ visual-c++ variadic-functions

C ++ 11标准指定vwscanf可通过标题<cwchar>(因此<wchar.h>)使用。但是,它似乎缺乏Visual C ++。有了这个功能,我可以写...

inline int scanf( CodingValue const* format, ... )
{
    va_list args;
    va_start( args, format );
    return ::vwscanf( format->ptr(), args );
}

但没有它,即使用Visual C ++ 10.0,它似乎也缺乏对C ++ 11可变参数模板的支持,我已经减少了写作......

inline int scanf(
    CodingValue const* format,
    void* a01 = 0, void* a02 = 0, void* a03 = 0, void* a04 = 0, void* a05 = 0,
    void* a06 = 0, void* a07 = 0, void* a08 = 0, void* a09 = 0, void* a10 = 0,
    void* a11 = 0, void* a12 = 0
    )
{
    int const   nArgs = !!a01 + !!a02 + !!a03 + !!a04 + !!a05 + !!a06 +
                        !!a07 + !!a08 + !!a09 + !!a10 + !!a11 + !!a12;
    BasicCodingValue const* const   f   = format->ptr();

    switch( nArgs )
    {
    case  0:    return ::wscanf( f );
    case  1:    return ::wscanf( f,a01 );
    case  2:    return ::wscanf( f,a01,a02 );
    case  3:    return ::wscanf( f,a01,a02,a03 );
    case  4:    return ::wscanf( f,a01,a02,a03,a04 );
    case  5:    return ::wscanf( f,a01,a02,a03,a04,a05 );
    case  6:    return ::wscanf( f,a01,a02,a03,a04,a05,a06 );
    case  7:    return ::wscanf( f,a01,a02,a03,a04,a05,a06,a07 );
    case  8:    return ::wscanf( f,a01,a02,a03,a04,a05,a06,a07,a08 );
    case  9:    return ::wscanf( f,a01,a02,a03,a04,a05,a06,a07,a08,a09 );
    case 10:    return ::wscanf( f,a01,a02,a03,a04,a05,a06,a07,a08,a09,a10 );
    case 11:    return ::wscanf( f,a01,a02,a03,a04,a05,a06,a07,a08,a09,a10,a11 );
    case 12:    return ::wscanf( f,a01,a02,a03,a04,a05,a06,a07,a08,a09,a10,a11,a12 );
    }
}

或者,我可以做一些集会,就像15年前我遇到类似(或者可能是同样的)问题时所做的那样,但这感觉不太合适。

你能建议一些更好的方法吗?

3 个答案:

答案 0 :(得分:2)

据我所知,用C语言中的额外(即多于要求)参数调用可变参数函数并不是错误(可能在C ++中,尽管我还没有找到确定的语句)。< / p>

到目前为止,我在C ++方面取得的最好成绩是5.2.2 [expr.call]:

  

可以声明一个函数接受较少的参数(通过声明   默认参数(8.3.6))或更多参数(通过使用省略号,   ...,或函数参数包(8.3.5))的数量   函数定义中的参数(8.4)

18.10 [support.runtime]遵循关于va_start()限制的ISO C 4.8.1.1。

我无法在任何地方看到“你不能传递额外的论点”,所以似乎认为它不被禁止是不合理的。

如果在C ++中提供额外的参数是不合法的,那么你可以使用C ++来处理默认参数并调用一个C函数,默认值已经“填写”,这样你就可以调用一个C函数,无论如何提出了多少论点。

所以在C ++中你会这样做:

extern "C" {
  int real_scanf(
        const char* format,
        void* a01, void* a02, void* a03, void* a04, void* a05,
        void* a06, void* a07, void* a08, void* a09, void* a10,
        void* a11, void* a12
        );
}

inline int scanf(
    CodingValue const* format,
    void* a01 = 0, void* a02 = 0, void* a03 = 0, void* a04 = 0, void* a05 = 0,
    void* a06 = 0, void* a07 = 0, void* a08 = 0, void* a09 = 0, void* a10 = 0,
    void* a11 = 0, void* a12 = 0
    )
{
    BasicCodingValue const* const   f   = format->ptr();
    return real_scanf( f,a01,a02,a03,a04,a05,a06,a07,a08,a09,a10,a11,a12 );
}

然后在C中你可以做到:

int real_scanf(
    const char* format,
    void* a01, void* a02, void* a03, void* a04, void* a05,
    void* a06, void* a07, void* a08, void* a09, void* a10,
    void* a11, void* a12
    )
{
    return wscanf( format,a01,a02,a03,a04,a05,a06,a07,a08,a09,a10,a11,a12 );
}

答案 1 :(得分:1)

我的awoodland的答案版本:默认值参数是必需的:

#include <cstdio>
#include <cassert>

template <typename CodingValue>
int scanf(CodingValue const* format,
    void* a01 = 0, void* a02 = 0, void* a03 = 0, void* a04 = 0, void* a05 = 0,
    void* a06 = 0, void* a07 = 0, void* a08 = 0, void* a09 = 0, void* a10 = 0,
    void* a11 = 0, void* a12 = 0)
{
    return wscanf( format,a01,a02,a03,a04,a05,a06,a07,a08,a09,a10,a11,a12 );
}

int main()
{
    int v(0);
    int rc = scanf<wchar_t>(L"%d", &v);
    assert(1 == rc);
    return 0;
}

请参阅上面的Dennis Zickefoose评论,了解一些背景细节。

答案 2 :(得分:0)

VS2010实现了int vwscanf(format, ...)

File = wscanf.c

目录= C:\ Program Files(x86)\ Microsoft Visual Studio 10.0 \ VC \ crt \ src