在msvc上替换vsscanf

时间:2010-03-16 19:12:22

标签: c++ c visual-c++

我遇到了将代码库从linux(gcc)移植到windows(msvc)的问题。看起来C99函数vsscanf不可用,没有明显的替代品。

我已经阅读了使用内部函数_input_l并静态链接到crt运行时的解决方案,但遗憾的是我无法静态链接,因为它会混淆应用程序加载的所有插件(如dll)。

那么有什么替代品或者为vsscanf编写包装器的方法吗?

更新2016-02-24

当第一次询问时,没有原生替代品,但从那以后MSVC已经实现了对此的支持以及更多。

  • VS2013后来实现了vsscanf和朋友。
  • C++11也包括支持。

6 个答案:

答案 0 :(得分:3)

应该有效的黑客攻击:

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... */);
}

将20替换为您认为可能需要的最大args数。这段代码不是非常便携,但它仅用于丢失vsscanf的一个特定的破碎系统,所以这并不重要。

答案 1 :(得分:0)

快速搜索提出了一些建议,包括http://www.flipcode.net/archives/vsscanf_for_Win32.shtml

答案 2 :(得分:0)

由于这是标记的C ++,您是否考虑过咬住子弹并完全离开scanf函数行? C ++习惯的方式是使用std::istringstream。重写使用它而不是寻找vsscanf替换可能更容易和更便携,更不用说具有更大的类型安全性。

答案 3 :(得分:0)

如果你想包装sscanf而你正在使用C ++ 11,你可以这样做:

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

要在msvc上运行,您需要下载此更新:

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

答案 4 :(得分:0)

有趣的是它在今天之前从来没有出现过。我可以发誓过去我曾经使用过这个功能。但无论如何,这是一个有效的解决方案,并且与您的参数和格式字符串一样安全:

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]);
}

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)); }

输出:

Arg1 = -52,arg2 = 456,arg3 = @ 按任意键继续 。 。 。

好吧,我无法正确的格式化,但你明白了。

答案 5 :(得分:0)

修改自: 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

仅在Visual Studio 2008上测试