Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
133 views
in Technique[技术] by (71.8m points)

c++ - Why does the same vsnprintf code output differently on Windows (MSVC) and Unix (Clang)

On Unix (Clang 3.8.1), this code outputs:

6: 32

8: a8e

On Windows (MSVC 19.00.24215.1), this code outputs:

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, '');
  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() << "
";
  std::cout << getFormattedString("a%de", 12345).c_str() << "
";

  return 0;
}

Interestingly, they both get the correct count, but on my Linux and OS X machines, this code outputs an incorrect result. What's causing this? Have I incurred UB somewhere?

question from:https://stackoverflow.com/questions/65879007/issue-with-vsnprintf-in-linux

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

As @RaymondChen said in the comments, vsnprintf modifies ap. If you want to reuse the va_list, you have to make a copy with 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, '');
    if (vsnprintf(&result[0], count, fmt, ap2) < 0) { return "error";}
    std::cout << result.size() << ' ' << strlen(result.c_str()) << '
';

    return result;
}

This will use the original list twice, and produce the correct result.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...