代码之家  ›  专栏  ›  技术社区  ›  user48956

VAX拷贝-移植到Visual C++?

  •  16
  • user48956  · 技术社区  · 16 年前

    A previous question 显示了一种很好的字符串打印方法。答案涉及到虚拟副本:

    std::string format (const char *fmt, ...);
    {
       va_list ap;
       va_start (ap, fmt);
       std::string buf = vformat (fmt, ap);
       va_end (ap);
       return buf;
    }
    
    
    std::string vformat (const char *fmt, va_list ap)
    {
       // Allocate a buffer on the stack that's big enough for us almost
       // all the time.
       s ize_t size = 1024;
       char buf[size];
    
       // Try to vsnprintf into our buffer.
       va_list apcopy;
       va_copy (apcopy, ap);
       int needed = vsnprintf (&buf[0], size, fmt, ap);
    
       if (needed <= size) {
           // It fit fine the first time, we're done.
           return std::string (&buf[0]);
       } else {
           // vsnprintf reported that it wanted to write more characters
           // than we allotted.  So do a malloc of the right size and try again.
           // This doesn't happen very often if we chose our initial size
           // well.
           std::vector <char> buf;
           size = needed;
           buf.resize (size);
           needed = vsnprintf (&buf[0], size, fmt, apcopy);
           return std::string (&buf[0]);
       }
    

    }

    我的问题是,上面的代码不能移植到VisualC++,因为它不提供VAIO拷贝(或者甚至是VAX拷贝)。那么,有人知道如何安全地移植上述代码吗?大概,我需要做一个va_拷贝,因为vsnprintf会破坏性地修改传递的va_列表。

    4 回复  |  直到 10 年前
        1
  •  14
  •   Adam Rosenfield    16 年前

    你应该能够逃脱常规任务的束缚:

    va_list apcopy = ap;
    

    它在技术上是不可移植和未定义的行为,但它将与大多数编译器和体系结构一起工作。在x86呼叫约定中, va_list S只是指向堆栈的指针,可以安全地进行复制。

        2
  •  9
  •   Steve K    12 年前

    对于Windows,您可以简单地定义va_copy yourself:

    #define va_copy(dest, src) (dest = src)
    
        3
  •  5
  •   Michael Burr    16 年前

    你可以做的一件事是如果你不需要 vformat() 函数,将其实现移入 format() 功能(未测试):

    #include <stdarg.h>
    #include <string.h>
    #include <assert.h>
    #include <string>
    #include <vector>
    
    
    std::string format(const char *fmt, ...)
    {
       va_list ap;
    
       enum {size = 1024};
    
       // if you want a buffer on the stack for the 99% of the time case 
       //   for efficiency or whatever), I suggest something like
       //   STLSoft's auto_buffer<> template.
       //
       //   http://www.synesis.com.au/software/stlsoft/doc-1.9/classstlsoft_1_1auto__buffer.html
       //
       std::vector<char> buf( size);
    
       //
       // where you get a proper vsnprintf() for MSVC is another problem
       // maybe look at http://www.jhweiss.de/software/snprintf.html
       //
    
       // note that vsnprintf() might use the passed ap with the 
       //   va_arg() macro.  This would invalidate ap here, so we 
       //   we va_end() it here, and have to redo the va_start()
       //   if we want to use it again. From the C standard:
       //
       //       The object ap may be passed as an argument to
       //       another function; if that function invokes the 
       //       va_arg macro with parameter ap, the value of ap 
       //       in the calling function is indeterminate and 
       //       shall be passed to the va_end macro prior to 
       //       any further reference to ap.   
       //
       //    Thanks to Rob Kennedy for pointing that out.
       //
       va_start (ap, fmt);
       int needed = vsnprintf (&buf[0], buf.size(), fmt, ap);
       va_end( ap);
    
       if (needed >= size) {
           // vsnprintf reported that it wanted to write more characters
           // than we allotted.  So do a malloc of the right size and try again.
           // This doesn't happen very often if we chose our initial size
           // well.
           buf.resize( needed + 1);
    
           va_start (ap, fmt);
           needed = vsnprintf (&buf[0], buf.size(), fmt, ap);
           va_end( ap);
    
           assert( needed < buf.size());
       }
    
       return std::string( &buf[0]);
    }
    
        4
  •  2
  •   thakis    10 年前

    va_copy() 直接支持从开始 Visual Studio 2013 . 所以,如果你可以依靠现有的资源,你就不需要做任何事情。