Лучший способ обойти отсутствие vwscanf в Visual C ++? - PullRequest
4 голосов
/ 03 ноября 2011

Стандарт C ++ 11 указывает, что vwscanf доступно через заголовок <cwchar> (и, следовательно, <wchar.h>). Однако в Visual C ++ этого, похоже, не хватает. С помощью этой функции я мог написать & hellip;

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

но без него, т. Е. С Visual C ++ 10.0, в котором также отсутствует поддержка вариабельных шаблонов C ++ 11, я уменьшен до написания & hellip;

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 ]

2 голосов
/ 03 ноября 2011

Насколько я понимаю, вызывать переменную функцию с дополнительными (т. Е. Более, чем запрашиваемыми) аргументами в C (и, возможно, в C ++, не является ошибкой), хотя в любом случае я еще не определил окончательное утверждение).

Лучшее, что у меня есть на стороне C ++, это 5.2.2 [expr.call]:

Функция может быть объявлена ​​для приема меньшего числа аргументов (путем объявления аргументов по умолчанию)(8.3.6)) или больше аргументов (с помощью многоточия, ... или пакета параметров функции (8.3.5)), чем число параметров в определении функции (8.4)

18.10 [support.runtime] ссылается на ISO C 4.8.1.1 на предмет ограничений для va_start().

Я не вижу нигде, где говорится, что «вы не должны передавать дополнительные аргументы», поэтомукажется, что было бы неразумно предполагать, что это не запрещено.

Если в 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 голос
/ 03 ноября 2011

Моя версия ответа 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 комментариям выше для некоторых деталей.

0 голосов
/ 03 ноября 2011

Существует реализация int vwscanf(format, ...) с VS2010.

File = wscanf.c

Directory = C: \ Program Files (x86) \ Microsoft Visual Studio 10.0 \ VC \ crt\ SRC

...