代码之家  ›  专栏  ›  技术社区  ›  John Hascall

如果格式字符串没有进行%引用,是否保证vsprintf()不访问va_列表?

  •  3
  • John Hascall  · 技术社区  · 6 年前

    如果将格式字符串传递给 vsprintf() (及其变体)不包含%引用,是否保证不访问va_list参数?

    换句话说,是:

    #include <stdarg.h>
    #include <stdio.h>
    int main ( void ) {
        char    str[16];
        va_list ap;         /* never initialized */
    
        (void)vsnprintf(str, sizeof(str), "", ap);
        return 0;
    }
    

    符合标准的程序?还是有未定义的行为?

    上面的例子显然是愚蠢的,但是想象一下一个函数,它可以同时被一个变量函数和一个固定的args函数调用,大致简化为:

    void somefuncVA ( const char * fmt, va_list ap ) {
        char    str[16];
        int     n;
    
        n = vsnprintf(str, sizeof(str), fmt, ap);
        /* potentially do something with str */
    }
    
    void vfoo ( const char * fmt, ... ) {
        va_list ap;
    
        va_start(fmt, ap);
        somefuncVA(fmt, ap);
    }
    
    void foo ( void ) {
        va_list ap;     /* no way to initialize this */
    
        somefuncVA("", ap);
    }
    
    2 回复  |  直到 6 年前
        1
  •  3
  •   chux    6 年前
    int vsprintf(char * restrict s, const char * restrict format, va_list arg);
    

    如果将格式字符串传递给 vsprintf() …不包含%引用,是否保证 va_list 无法访问参数。

    不.

    这个 vsprintf 函数等价于 sprintf ,使用变量参数列表 替换为 arg ,其中 应已初始化 va_start 宏。。。。。
    C11DR第7.21.6.13条

    由于以下代码不符合规范,因此结果是 未定义的行为 (乌布)。没有保证。 @Eugene Sh.

    va_list ap;
    //                                    vv-- ap not initialized
    (void)vsnprintf(str, sizeof(str), "", ap);
    

    vsprintf()。 保证不进入 列表 如果格式字符串不引用%

    正确通过 va_list arg , vsprintf()。 表现得像 sprintf() . 这样的代码是可以的。允许传递额外的参数。通孔 vsprintf()。 ,它们(额外参数)尚未被访问。 变量列表参数 可以访问。

    sprintf(buf, "format without percent", 1.2345, 456)`
    
        2
  •  3
  •   Andrew Henle    6 年前

    如果您没有将varargs传递给您的函数-您的函数没有用 ... 作为最后一个参数-根本不需要使用 va_list va_start() 在那个函数中。如果要传递一组空的变量参数,只需直接调用varargs函数而不使用任何变量参数-例如, printf("\n"); .

    例如,而不是

    void foo ( void ) {
        va_list ap;     /* no way to initialize this */
    
        somefuncVA("", ap);
    }
    

    你可以只写

    void foo ( void ) {
        vfoo("");
    }