任何避免警告 C6386 的方法,无需禁用它或完全代码分析

Any way to avoid warning C6386, without disabling it or Code Analysis altogether

Visual Studio 2019 年开始默认将代码分析警告显示为编辑器内的绿色波浪线。这些对于学习 C 编程的学生来说可能非常有用,因为它们可以捕捉到经典错误,例如访问一个数组时偏离。

不幸的是,误报可能会完全破坏学习体验,我担心我将不得不要求学生禁用该功能以避免让他们担心不存在的问题。

这个简短的片段不会引起任何警告:

#include <stdlib.h>

int main(void)
{
    size_t n = 6;
    int *v = malloc(n * sizeof(int));
    if (v == NULL) {
        return 1;
    }
    for (size_t i = 0; i < n; ++i) {
        v[i] = i;
    }
    free(v);
    return 0;
}

不幸的是,如果您在函数中移动分配,如下所示:

#include <stdlib.h>

int *test(size_t n)
{
    int *v = malloc(n * sizeof(int));
    if (v == NULL) { 
        return NULL;
    }
    for (size_t i = 0; i < n; ++i) {
        v[i] = i;
    }
    return v;
}

int main(void)
{
    size_t n = 6;
    int *v = test(n);   
    free(v);
    return 0;
}

你得到一个warning C6386: Buffer overrun while writing to 'v': the writable size is 'n*sizeof(int)' bytes, but '8' bytes might be written.

即使在 Stack Overflow 上阅读,我也不知道 '8' 的来源,但更重要的是,为什么它无法识别 i 永远不会超出范围。

所以问题是:有没有办法以不会生成警告的方式编写此类代码?

我知道我可以转到 Tools > Options > Text Editor > C/C++ > Experimental > Code Analysis 并将 Disable Code Analysis Squiggles 设置为 True,或者使用 #pragma warning(disable:6386),但我宁愿避免它,当然避免向我的学生推荐后者。

您可以取消此警告(可能 被视为错误),只需确保提供给 malloc 调用的 n 的值具有不会在溢出后“环绕”(如 中所暗示)。

为此,您可以将 n 参数替换为看似奇怪的 max(n,0):

int* test(size_t n)
{
//  int* v = malloc(n * sizeof(int));         // Warning C6386 on v[i] = i
    int* v = malloc(max(n, 0) * sizeof(int)); // No warning
    if (v == NULL) {
        return NULL;
    }
    for (size_t i = 0; i < n; ++i) {
        v[i] = i;
    }
    return v;
}

我真的很想感谢大家的贡献,我同意 it is a bug in the Code Analyzer(通过查看 Microsoft 网站,两年前它已经“关闭 - 低优先级”...)。

Adrian Mole max(n, 0) 技巧指出了一种处理代码警告的方法,即检查 n 是否大于零。有趣的是,您仍然可以将那个零用于应该使用 n 的地方。虽然这个想法可以用于有经验的程序员(这可能会禁用警告),但正如 John Bollinger 指出的那样,它不适合学生。

因此,在告诉学生这是一个错误 以及如何关闭代码分析曲线或禁用警告之后,我会选择

int *test(size_t n)
{
    if (n == 0) {
        return NULL;
    }
    int *v = malloc(n * sizeof(int));
    if (v == NULL) {
        return NULL;
    }
    for (size_t i = 0; i < n; ++i) {
        v[i] = i;
    }
    return v;
}

这也可以解释为:不允许分配 0 个元素。