【问题标题】:va_start - difference between 32 and 64-bit build [duplicate]va_start - 32 位和 64 位版本之间的区别 [重复]
【发布时间】:2018-05-11 22:07:56
【问题描述】:

我编写此代码是为了对 std::string 使用 sprintf 样式的格式。

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

std::string formatstr(const std::string &fmt, ...)
{
    const char *fmt_s(fmt.c_str());
    std::vector<char> buf(256);
    va_list args;
    va_start(args, &fmt);
    auto n = -1;
    while ((n = vsnprintf(&buf[0], buf.size() - 1, fmt_s, args)) == -1)
        buf.resize(2 * buf.size());
    va_end(args);
    std::string text(&buf[0]);
    return text;
}

int main(int argc, char** argv)
{
    std::string s = "Instrument label: %s";
    std::cout << formatstr(s, "Frequency Generator") << "\n";

    return EXIT_SUCCESS;
}

输出:

仪器标签:频率发生器

它在 64 位版本中运行良好。

但是,一旦我将配置更改为 32 位,VS 编辑器就会在 va_start 下添加小红色波浪线错误行并抱怨:表达式必须是左值或 xvalue

我的 64 位版本可以正常工作是一个错误吗?还是 Visual Studio 中的一个错误,它不适用于 32 位?有什么根本区别吗?

【问题讨论】:

  • 这只是一个智能感知错误还是您实际上得到了一个编译器错误?如果您关闭并重新打开已选择 32 位的项目怎么办?
  • @RetiredNinja 这不仅仅是智能感知。它实际上不会让我以 32 位编译它。我只是尝试关闭并重新打开,但它没有帮助。此外,该项目是新的和最小的 - 我只是为了测试这个代码(对于这个问题)。
  • @nvd 好的,我承认它可以被解释为重复。奇怪的是,它在 64 位版本中运行良好。我实际上已经使用它一段时间了,只是现在才在 32 位版本中尝试过。
  • 使用 C++ 风格 operator&lt;&lt; 或可变参数模板有什么问题?这比尝试使用 printf 样式要安全得多。
  • 你不能用同一个 va_list 对象调用 vsnprintf 两次,因为“当这些函数调用 va_arg 宏时,返回后 ap 的值是未指定的。”也许 Windows 可以让你侥幸逃脱,但代码不会是可移植的。另外,从VS2015开始,vsnprintf符合C99;如果缓冲区太短,它不再返回 -1。见msdn.microsoft.com/en-us/library/1kt27hek.aspx#Return%20Value

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


【解决方案1】:

尝试将va_start(args, &amp;fmt) 替换为va_start(args, fmt)

文档 (http://www.cplusplus.com/reference/cstdarg/va_start/) 并未指出需要指向参数的指针,而是应该是变量参数之前的参数名称:...

编辑:另见varargs(va_list va_start) doesn't work with pass-by-reference parameter

因此,为了修复它,您可以使用指针而不是 fmt 的引用,这给出了这个“修复”(您可能不喜欢它......)

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

std::string formatstr(const std::string *fmt, ...)
{
    const char *fmt_s(fmt->c_str());
    std::vector<char> buf(256);
    va_list args;
    va_start(args, fmt);
    auto n = -1;
    while ((n = vsnprintf(&buf[0], buf.size() - 1, fmt_s, args)) == -1)
        buf.resize(2 * buf.size());
    va_end(args);
    std::string text(&buf[0]);
    return text;
}

int main(int argc, char** argv)
{
    std::string s = "Instrument label: %s";
    std::cout << formatstr(&s, "Frequency Generator") << "\n";

    return EXIT_SUCCESS;
}

【讨论】:

  • 这将消除编辑器中的警告,但不会编译。
  • @BlairFonville 究竟是什么编译器错误?
  • 它确实需要一个指针。如果函数的参数是“const char *fmt”,那么 va_start(args, fmt) 可以正常工作。
  • 您是指我的代码还是您的代码的编译器错误?
  • 我需要编译器错误,并提供我提供的“修复”
猜你喜欢
  • 2017-07-29
  • 2014-08-09
  • 2017-07-01
  • 2011-12-12
  • 1970-01-01
  • 2011-09-13
  • 2015-07-18
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多