【问题标题】:Why declare a va_list inside a for loop?为什么要在 for 循环中声明 va_list?
【发布时间】:2020-10-28 21:10:25
【问题描述】:

以下代码来自更好的字符串库头。 在查看定义宏时,我注意到 va_list、va_start 和 va_end 都在 for 循环中使用。

想知道为什么这是必要的吗?

顺便说一句,我研究了不修改 bstrmp_arglist 的函数 bvcformata。

#define bvformata(ret, b, fmt, lastarg) { \
        bstring bstrtmp_b = (b); \
        const char * bstrtmp_fmt = (fmt); \
        int bstrtmp_r = BSTR_ERR, bstrtmp_sz = 16; \
        for (;;) { \
                va_list bstrtmp_arglist; \
                va_start (bstrtmp_arglist, lastarg); \
                bstrtmp_r = bvcformata (bstrtmp_b, bstrtmp_sz, bstrtmp_fmt, bstrtmp_arglist); \
                va_end (bstrtmp_arglist); \
                if (bstrtmp_r >= 0) { /* Everything went ok */ \
                        bstrtmp_r = BSTR_OK; \
                        break; \
                } else if (-bstrtmp_r <= bstrtmp_sz) { /* A real error? */ \
                        bstrtmp_r = BSTR_ERR; \
                        break; \
                } \
                bstrtmp_sz = -bstrtmp_r; /* Doubled or target size */ \
        } \
        ret = bstrtmp_r; \
}

#endif

是否可以将 va_list、va_start 和 va_end 从 for 循环中“移出”?我仍然是 C 的初学者。只是想知道为什么必须在 for 循环中使用它们?

#define bvformata(ret, b, fmt, lastarg) { \
        bstring bstrtmp_b = (b); \
        const char * bstrtmp_fmt = (fmt); \
        int bstrtmp_r = BSTR_ERR, bstrtmp_sz = 16; \
        va_list bstrtmp_arglist; \             <--------*****
        va_start (bstrtmp_arglist, lastarg); \ <--------*****
        for (;;) { \
                bstrtmp_r = bvcformata (bstrtmp_b, bstrtmp_sz, bstrtmp_fmt, bstrtmp_arglist); \
                
                if (bstrtmp_r >= 0) { /* Everything went ok */ \
                        bstrtmp_r = BSTR_OK; \
                        break; \
                } else if (-bstrtmp_r <= bstrtmp_sz) { /* A real error? */ \
                        bstrtmp_r = BSTR_ERR; \
                        break; \
                } \
                bstrtmp_sz = -bstrtmp_r; /* Doubled or target size */ \
        } \
        va_end (bstrtmp_arglist); \ <--------*****
        ret = bstrtmp_r; \
}

#endif

【问题讨论】:

  • 如果va_list 是一个指针,我认为不能保证va_arg() 不会取消引用指针并修改其内容。
  • 如果我在我们公司的代码中看到这种宏我会强迫作者在黑板上写1000遍“我再也不会写这种东西了”i.stack.imgur.com/P5Zdr.jpg

标签: c


【解决方案1】:

您可以将va_list 声明移到循环之外。但是va_startva_end 必须留在循环中,这样每次对bvcformata() 的调用都会从头开始处理变量参数。

#define bvformata(ret, b, fmt, lastarg) { \
        bstring bstrtmp_b = (b); \
        const char * bstrtmp_fmt = (fmt); \
        int bstrtmp_r = BSTR_ERR, bstrtmp_sz = 16; \
        va_list bstrtmp_arglist; \
        for (;;) { \
                va_start (bstrtmp_arglist, lastarg); \
                bstrtmp_r = bvcformata (bstrtmp_b, bstrtmp_sz, bstrtmp_fmt, bstrtmp_arglist); \
                va_end (bstrtmp_arglist); \
                if (bstrtmp_r >= 0) { /* Everything went ok */ \
                        bstrtmp_r = BSTR_OK; \
                        break; \
                } else if (-bstrtmp_r <= bstrtmp_sz) { /* A real error? */ \
                        bstrtmp_r = BSTR_ERR; \
                        break; \
                } \
                bstrtmp_sz = -bstrtmp_r; /* Doubled or target size */ \
        } \
        ret = bstrtmp_r; \
}

#endif

【讨论】:

    【解决方案2】:

    别介意傻我。我只是注意到 for 循环中有“break”。通过“移动” va_list 和 va_end 会造成内存泄漏。

    【讨论】:

    • 你为什么这么认为?您更新的代码在循环外调用va_end
    猜你喜欢
    • 2021-07-23
    • 1970-01-01
    • 2011-09-02
    • 1970-01-01
    • 2015-03-25
    • 2015-08-04
    • 1970-01-01
    • 1970-01-01
    • 2018-04-25
    相关资源
    最近更新 更多