【问题标题】:vsnprintf() on Mac gives EXC_BAD_ACCESS?Mac 上的 vsnprintf() 给出 EXC_BAD_ACCESS?
【发布时间】:2014-04-18 15:46:40
【问题描述】:

我不确定为什么会在以下代码中看到 EXC_BAD_ACCESS:

template <typename ArgType>
String Format(ArgType args, ...) const {
    va_list argList;
    va_start(argList, args);

    // determine num of chars needed, don't store anything anywhere though!
    size_t charsNeeded = vsnprintf(NULL, 0, ToStdString().c_str(), argList);

    va_end(argList);

    // print formatted string into buf
    va_start(argList, args); // EDIT: new va_list here
    char buf[charsNeeded];
    vsprintf(buf, ToStdString().c_str(), argList);

    va_end(argList);

    return String(buf);
}

编辑:我可能应该提到代码应该这样使用:

String str = String("Hello, %s!").Format("World");

我应该提到 String 是一个小型包装类,它有一个 ToStdString() 方法,该方法返回一个 std::string 成员 var。

vsnprintf() 调用出现段错误,但我不知道为什么!

【问题讨论】:

  • vsnprintf 的调用可能由于格式说明符与传递给Format 的数据不匹配而失败。 FWIW 可变长度数组 (char buf[charsNeeded]) 不是标准 C++。
  • 您是否打算忽略使用args 处理anything? ?即使调用成功,VLA 也只有一个字符,因为charsNeeded 不会包含终止符所需的 +1。为了理智起见,将ToStdString() 填入实际的std::string,然后使用its c_str()。无论如何,我认为没有理由使用 VLA。使用std::vector&lt;&gt;
  • 你是什么意思“的” vsnprintf 调用?有两个,如果 charsNeeded 太大,您可能会遇到一些依赖于操作系统的故障 - 在 mac 上可能是 EXC_BAD_ACCESS 吗?
  • @loreb:只有一个调用vsnprintf(),另一个调用vsprintf(),注意缺少n
  • 无关:但arglistvsnprintf() 将返回后无效。

标签: c++ variadic-functions printf


【解决方案1】:

va_start 初始化 va_list 以获取指定参数之后的参数,因为在您的示例中,您只向方法发送一个参数,va_list 为空。

您还需要在调用vsnprintf 后重新初始化va_list

你需要重新考虑你的方法的签名,可以做一个静态函数:

class String : public std::string {
public:
    String(std::string str) : std::string(str) {}

    String(char *str) : std::string(str) {}

    static String Format(String format, ...) {
        va_list argList;
        va_start(argList, format);

        // determine num of chars needed, don't store anything anywhere though!      
        size_t charsNeeded = vsnprintf(NULL, 0, format.c_str(), argList);

        va_end(argList);
        va_start(argList, format);

        // print formatted string into buf                                           
        char buf[charsNeeded];
        vsprintf(buf, format.c_str(), argList);

        va_end(argList);

        return String(buf);
    }
};

编辑:

如果您要格式化字符串,最好的解决方案可能是使用std::stringstream:http://www.cplusplus.com/reference/sstream/stringstream/stringstream/

【讨论】:

  • 好主意,它是静态的。虽然我更喜欢它作为实例方法,但我想真的 static 更有意义,并且意味着 vsprintf() 将正常工作!
  • 哦,还有一件小事,我们需要在第二个 va_start(argList, format); 之前使用 va_end(argList) 吗? ?
  • 在阅读 va_end 手册页后,我添加了对 va_end 的第二次调用:Note that each call to va_start() must be matched by a call to va_end(), from within the same function. 您可能应该考虑返回 String *,因为返回 String 意味着副本已制作完成,对于长字符串,这可能会占用大量内存。
  • 虽然这是正确的,但将vsnprintf 的结果隐式转换为size_t 并不是一个好主意。如果发生错误,它会返回一个负值,并且您将其丢弃。
猜你喜欢
  • 2022-01-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-10-05
  • 1970-01-01
  • 1970-01-01
  • 2017-03-23
相关资源
最近更新 更多