为什么这段代码会触发;写入超限警告(C6386)";使用MSVS2012

为什么这段代码会触发;写入超限警告(C6386)";使用MSVS2012,c,C,我有以下一段C代码: #include <stdint.h> typedef union{ uint8_t c[4]; uint16_t s[2]; uint32_t l; }U4; uint32_t cborder32(uint32_t l) { U4 mask,res; unsigned char* p = (unsigned char*)&l; mask.l = 0x00010203; res.c[(uint8

我有以下一段C代码:

#include <stdint.h>

typedef union{
    uint8_t c[4];
    uint16_t s[2];
    uint32_t l;
}U4;

uint32_t cborder32(uint32_t l)
{
    U4 mask,res;
    unsigned char* p = (unsigned char*)&l;
    mask.l = 0x00010203;
    res.c[(uint8_t)(mask.c[0])] = (uint8_t)p[0]; // <-- this line gives C6386
    res.c[(uint8_t)(mask.c[1])] = (uint8_t)p[1];
    res.c[(uint8_t)(mask.c[2])] = (uint8_t)p[2];
    res.c[(uint8_t)(mask.c[3])] = (uint8_t)p[3];
    return res.l;
}
#包括
typedef联合{
uint8_t c[4];
uint16_t s[2];
uint32_t l;
}U4;
uint32\u t cborder32(uint32\u t l)
{
U4掩模,res;
无符号字符*p=(无符号字符*)&l;
掩码l=0x00010203;
res.c[(uint8_t)(mask.c[0])]=(uint8_t)p[0];/我认为这是Microsoft产品中的一个潜在缺陷。在计算数组索引时,它似乎使用了
mask.l
0x01020304
为十进制
66051
)的完整值,尽管您显然需要
mask.c[0]
强制为
uint8\t

第一步是通知微软。他们可能会回来告诉你你错了,希望给你C++的标准部分,说明你为什么做的是错误的。或者他们可能只是说代码分析工具是“最好的努力”。因为它实际上并不能阻止你编译。(而且在编译过程中不会产生错误或警告),他们仍然可以声称VC++是兼容的

当然,我希望他们不要采取这种做法,因为他们对确保自己的工具是最好的非常感兴趣


您应该采取的第二步是,首先要问为什么要以这种方式进行操作。您拥有的似乎是一个基于掩码的简单字节排序切换器。声明:

res.c[(uint8_t)(mask.c[0])] = (uint8_t)p[0];
无论如何都是有问题的,因为
(uint8_t)(mask.c[0])
的计算结果可能大于3,在这种情况下,您将在工会结束后继续写作

您可能认为确保
掩码
的字节数不大于
3
可能会阻止这种情况发生,但可能是分析仪不知道这一点。在任何情况下,已经有很多方法可以切换字节顺序,例如使用
htons
函数系列,或者,因为您的东西无论如何都是硬编码的,所以只需使用以下方法之一:

res.c[0] = p[0]; res.c[1] = p[1]; res.c[2] = p[2]; res.c[3] = p[3];
或:

或其他要求。使用此方法根本不会引起分析仪的任何投诉


如果您真的想使用当前的
掩码
方法执行此操作,您可以通过临时消除分析仪警告(至少在我正在使用的VS2013中)来消除分析仪警告(对于一行):


(由于类型已正确,已删除强制类型转换)。

mask.c[0..3]
:可能处于超出范围的值(超出0-3)你知道这会根据endianness给出不同的结果,是吗?也许你的代码分析器是错的。注意66051==3+2*256+65536,这是mask.lClang编译时没有警告,运行正常。如果你尝试运行它,你会有什么体验?
res.c[0] = p[3]; res.c[1] = p[2]; res.c[2] = p[1]; res.c[3] = p[0];
#pragma warning(suppress : 6386)
res.c[mask.c[0]] = p[0];
res.c[mask.c[1]] = p[1];
res.c[mask.c[2]] = p[2];
res.c[mask.c[3]] = p[3];