首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >关于vsnprintf (面试)

关于vsnprintf (面试)
EN

Stack Overflow用户
提问于 2012-04-09 06:10:19
回答 5查看 5.4K关注 0票数 3

在一次面试中,我被要求(除其他外)履行以下职能:

代码语言:javascript
复制
int StrPrintF(char **psz, const char *szFmt, ...);

类似于sprintf,除了已经分配的存储之外,函数必须自己分配它,并在*psz变量中返回。此外,*psz可能指向一个已经分配的字符串(堆上),该字符串可能在格式化期间使用。当然,这个字符串必须以适当的方式释放。

返回值应该是新创建的字符串的长度,如果出现错误,则为负值。

这就是我的实现:

代码语言:javascript
复制
int StrPrintF(char **psz, const char *szFmt, ...)
{
    va_list args;
    int nLen;

    va_start(args, szFmt);

    if ((nLen = vsnprintf(NULL, 0, szFmt, args)) >= 0)
    {
        char *szRes = (char*) malloc(nLen + 1);
        if (szRes)
            if (vsnprintf(szRes, nLen + 1, szFmt, args) == nLen)
            {
                free(*psz);
                *psz = szRes;
            }
            else
            {
                free(szRes);
                nLen = -1;
            }
        else
            nLen = -1;
    }

    va_end(args);
    return nLen;
}

这个问题的作者声称在这个实现中有一个错误。这不仅是一个标准的违规行为,在特定的神秘系统上可能会失败,而是一个“真正的”错误,在大多数系统上,这可能是偶然的失败。

它也与int的使用无关,而与内存功能相适应的类型无关,例如size_tptrdiff_t。比如说,字符串的大小是“合理的”。

我真的不知道这个虫子会是什么。所有指针算法都是ok的,IMHO。我甚至不认为vsnprintf的两个后续调用会产生相同的结果。所有的各种处理的东西也是正确的IMHO。不需要va_copy (使用va_list的是被调用方的责任)。在x86上,va_copyva_end也是毫无意义的。

如果有人能发现(潜在的)错误,我会很感激的。

编辑:

在查看了答案和评论之后,我想添加一些注释:

  • 自然地构建并运行了具有各种输入的代码,包括在调试器中一步一步地观察变量状态。我从来不会在不亲自尝试的情况下寻求帮助。我没有看到任何问题,没有堆栈/堆损坏等等。我也在调试构建中运行过,启用了调试堆(这对堆corruption).
  • I是不容忍的,假设函数是用有效的参数调用的,即psz是一个有效的指针(不要与*psz混淆),szFmt是一个有效的格式说明符,并根据string.
  • Calling指针的standard.
  • Calling、vsnprintfNULL指针和size=0,对所有的变量参数进行了求值和对应格式的NULLfree和size=0。它应该返回得到的字符串长度。MS版本,虽然不完全符合标准,但在这个特定的case.
  • vsnprintf中也不会超过指定的缓冲区大小,包括0-结束符。意思是-它并不总是放置它。
  • 请把编码风格放在一边(如果你不喜欢的话--跟我说得好)。
EN

回答 5

Stack Overflow用户

回答已采纳

发布于 2012-04-09 08:14:09

不需要

va_copy (使用va_list的被调用方的责任)

不太对。我在vsnprintf标准中没有发现任何这样的要求。它在脚注中确实提到了这一点:

作为函数vfprintf、vscanf、vprintf、vscanf、vsnprintf、vsprintf和vscanf调用va_arg宏,返回后的arg值是不确定的

当您调用vsnprintf时,可以通过值或引用传递va_list (对于我们所知,它是一个不透明的类型)。所以第一个vsnprintf实际上可以修改va_list并破坏第二个东西。推荐的方法是使用va_copy制作一个副本。

事实上,根据this article的说法,这种情况在x86上不是这样发生的,而是在x64上发生的。

票数 9
EN

Stack Overflow用户

发布于 2014-04-09 17:58:34

对vsnprintf()的第一个调用实际上是试图获取最终字符串的长度。然而,它有一个副作用!它还将变量参数移到列表中的下一个变量。因此,下一个对vsnprintf()的调用在捕获的列表中没有第一个参数。简单的方法是,一旦从第一个vsnprintf()获得长度,就重新设置变量参数列表。也许还有其他更好的方法,但是,是的,这就是问题所在。

票数 1
EN

Stack Overflow用户

发布于 2012-04-09 06:25:35

根据以下内容,vsnprintf的第一个参数不应为null:

http://msdn.microsoft.com/en-us/library/1kt27hek(v=vs.80).aspx

编辑1:如果它是空的,你不应该释放*psz!

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/10069597

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档