开发者

Replacement for vsscanf on msvc

I've run into an issue porting a codebase from linux (gcc) to windows (msvc). It seems like the C99 function vsscanf isn't available and has no obvious replacement.

I've read about a solution using the internal function _input_l and linking statically to the crt runtime, but unfortunately I cannot link statically since it would mess with all the plugins (as dlls) being loaded by the application.

So is there any replacement or a way to write a wr开发者_如何学Pythonapper for vsscanf?

Update 2016-02-24:

When this was first asked there was no native replacement but since then MSVC has implemented support for this and much more.

  • VS2013 and later implements vsscanf and friends.
  • C++11 includes support as well.


A hack that should work:

int vsscanf(const char *s, const char *fmt, va_list ap)
{
  void *a[20];
  int i;
  for (i=0; i<sizeof(a)/sizeof(a[0]); i++) a[i] = va_arg(ap, void *);
  return sscanf(s, fmt, a[0], a[1], a[2], a[3], a[4], a[5], a[6], /* etc... */);
}

Replace 20 with the max number of args you think you might need. This code isn't terribly portable but it's only intended to be used on one particular broken system missing vsscanf so that shouldn't matter so much.


A quick search turned up several suggestions, including http://www.flipcode.net/archives/vsscanf_for_Win32.shtml


As this is tagged C++ have you considered just biting the bullet and moving away from the scanf line of functions completely? The C++ idiomatic way would be to use a std::istringstream. Rewriting to make use of that instead of looking for a vsscanf replacement would possibly be easier and more portable, not to mention having much greater type safety.


Funny it never came up for me before today. I could've sworn I'd used the function in the past. But anyway, here's a solution that works and is as safe as your arguments and format string:

template < size_t _NumArgs >

int VSSCANF_S(LPCTSTR strSrc, LPCTSTR ptcFmt, INT_PTR (&arr)[_NumArgs]) {

class vaArgs
      {
      vaArgs() {}
      INT_PTR* m_args[_NumArgs];
      public:
         vaArgs(INT_PTR (&arr)[_NumArgs])
                {
                for(size_t nIndex=0;nIndex<_NumArgs;++nIndex)
                    m_args[nIndex] = &arr[nIndex];
                }
      };

   return sscanf_s(strSrc, ptcFmt, vaArgs(arr));
   }

///////////////////////////////////////////////////////////////////////////////

int _tmain(int, LPCTSTR argv[])

{
INT_PTR args[3];
int nScanned = VSSCANF_S(_T("-52 Hello 456 @"), _T("%d Hello %u %c"), args);

return printf(_T("Arg1 = %d, arg2 = %u, arg3 = %c\n"), args[0], args[1], args[2]);
}

Out:

Arg1 = -52, arg2 = 456, arg3 = @ Press any key to continue . . .

Well I can't get the formatting right but you get the idea.


if you want to wrap sscanf and you are using C++11, you can do this:

template<typename... Args>
int mysscanf(const char* str, const char* fmt, Args... args) {
  //...
  return sscanf(str, fmt, args...);
}

to make this work on msvc, you need to download this update:

http://www.microsoft.com/en-us/download/details.aspx?id=35515


modified from : http://www.gamedev.net/topic/310888-no-vfscanf-in-visual-studio/

#if defined(_WIN32) && (_MSC_VER <= 1500)
static int vsscanf(
    const char  *buffer,
    const char  *format,
    va_list     argPtr
)
{
    // Get an upper bound for the # of args
    size_t count = 0;
    const char* p = format;
    while(1)
    {
        char c = *(p++);
        if (c == 0) 
            break;
        if (c == '%' && (p[0] != '*' && p[0] != '%')) 
            ++count;
    }
    if (count <= 0)
        return 0;
    int result;
    // copy stack pointer
    _asm
    {
        mov esi, esp;
    }
    // push variable parameters pointers on stack
    for (int i = count - 1; i >= 0; --i)
    {
        _asm
        {
            mov eax, dword ptr[i];
            mov ecx, dword ptr [argPtr];
            mov edx, dword ptr [ecx+eax*4];
            push edx;
        }
    }
    int stackAdvance = (2 + count) * 4;
    _asm
    {
        // now push on the fixed params
        mov eax, dword ptr [format];
        push eax;
        mov eax, dword ptr [buffer];
        push eax;
        // call sscanf, and more the result in to result
        call dword ptr [sscanf];
        mov result, eax;
        // restore stack pointer
        mov eax, dword ptr[stackAdvance];
        add esp, eax;
    }
    return result;
}
#endif // _WIN32 / _MSC_VER <= 1500

tested only on Visual Studio 2008

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜