为什么在Windows(MSVC)和Unix(Clang)上相同的vsnprintf代码输出不同

时间:2017-01-25 15:35:55

标签: c++ windows unix printf

在Unix(Clang 3.8.1)上,此代码输出:

  

6:32

     

8:a8e

在Windows(MSVC 19.00.24215.1)上,此代码输出:

  

6:12345

     

6:a12345e

#include <iostream>
#include <stdarg.h>

static std::string getFormattedString(const char* fmt, va_list ap) {
  int count = vsnprintf(NULL, 0, fmt, ap) + 1;
  std::cout << count << ": ";
  if (count <= 0) { return "unable to format message"; }

  std::string result = std::string(count, '\0');
  if (vsnprintf(&result[0], count, fmt, ap) < 0) { return "error";}

  return result;
}

static std::string getFormattedString(const char* fmt, ...) {
  va_list ap;
  va_start(ap, fmt);
  std::string result = getFormattedString(fmt, ap);
  va_end(ap);
  return result;
}

int main(int argc, char *argv[]) {
  std::cout << getFormattedString("%d", 12345).c_str() << "\n";
  std::cout << getFormattedString("a%de", 12345).c_str() << "\n";

  return 0;
}

有趣的是,它们都得到了正确的计数,但在我的Linux和OS X机器上,此代码输出的结果不正确。是什么导致了这个?我在某处招致了UB吗?

1 个答案:

答案 0 :(得分:3)

正如@RaymondChen在评论中所说,vsnprintf修改ap。如果要重用va_list,则必须使用va_copy创建副本:

static std::string getFormattedString(const char* fmt, va_list ap) {
    va_list ap2;
    va_copy(ap2, ap);
    int count = vsnprintf(NULL, 0, fmt, ap) + 1;
    std::cout << count << ": ";
    if (count <= 0) { return "unable to format message"; }

    std::string result = std::string(count, '\0');
    if (vsnprintf(&result[0], count, fmt, ap2) < 0) { return "error";}
    std::cout << result.size() << ' ' << strlen(result.c_str()) << '\n';

    return result;
}

这将使用原始列表两次,并产生正确的结果。