理解子表达式溢出推理
Understanding the Sub-expression overflow reasoning
我试图理解 Visual Studio 2022 年这一特定建议背后的原因,因为它对我来说似乎没有意义。这是简单的代码:
static constexpr uint32_t MAX_ELEMENTS = 100000;
const std::vector<int> A{ some random ints };
std::vector<bool> found(MAX_ELEMENTS);
for (int value : A)
{
if (value > 0 && value <= MAX_ELEMENTS)
found[value - 1] = true; // Problem it complains about is the value - 1.
}
这表明 “子表达式在添加到更宽的类型之前可能会溢出”。现在显然条件-if 阻止了这种情况的发生,但这里的推理是什么?
现在,如果这是 Spectre 的事情,我可以理解编译器会添加一个内存栅栏来停止 if 之后语句的任何推测执行,但我认为这不是这里的答案。
我唯一的想法是它与向量上的下标运算符有关;它的索引是一个大于 int 的类型并且被隐式转换为 size_t?
下面的问题似乎有点不直观:
found[value - 1]
这样做非常好,
int a = value - 1;
found[a];
当最终结果相同时。就理解而言,我在这里缺少什么?
在这种情况下,正如您所怀疑的那样,这是一个误报。这是一条有时会在更严格的代码库中使用的规则。 (例如,此特定警告是 MISRA 中的错误。)
很多警告都是这样的...编译器编写者正在尝试检测程序行为意外或无意的情况,但警告不是总是正确的。例如,
uint64_t x = 0xffffffffu << 16;
在具有 32 位 int 的系统上,标准是非常清楚这个值应该是什么...应该是:
uint64_t x = 0xffff0000u;
但是,它 看起来 就像有人打算写这个:
uint64_t x = (uint64_t)0xffff0000 << 16;
这就是警告试图捕捉到的内容。这就是这条规则背后的推理。在你的情况下,编译器做得不好。
您可以在编译器文档中看到更详细的警告理由:Warning C26451。
幽灵与它无关。
完全没问题...
为此:
int a = value - 1;
found[a];
在这种情况下,“意图”更为明显,因为程序员已明确将“int”写为类型。
解决方案
这是一个代码风格问题,因此有几种不同的解决方案,您可以选择一个您觉得合适的解决方案。
保持警告开启(嘈杂,可能会分散您对真正警告的注意力)
首先将表达式分配给一个 int(详细)
禁用整个代码库的警告(如果您认为它没有帮助)
使用 #pragma warning
(非常详细)
禁用此位置周围的警告
我试图理解 Visual Studio 2022 年这一特定建议背后的原因,因为它对我来说似乎没有意义。这是简单的代码:
static constexpr uint32_t MAX_ELEMENTS = 100000;
const std::vector<int> A{ some random ints };
std::vector<bool> found(MAX_ELEMENTS);
for (int value : A)
{
if (value > 0 && value <= MAX_ELEMENTS)
found[value - 1] = true; // Problem it complains about is the value - 1.
}
这表明 “子表达式在添加到更宽的类型之前可能会溢出”。现在显然条件-if 阻止了这种情况的发生,但这里的推理是什么?
现在,如果这是 Spectre 的事情,我可以理解编译器会添加一个内存栅栏来停止 if 之后语句的任何推测执行,但我认为这不是这里的答案。
我唯一的想法是它与向量上的下标运算符有关;它的索引是一个大于 int 的类型并且被隐式转换为 size_t?
下面的问题似乎有点不直观:
found[value - 1]
这样做非常好,
int a = value - 1;
found[a];
当最终结果相同时。就理解而言,我在这里缺少什么?
在这种情况下,正如您所怀疑的那样,这是一个误报。这是一条有时会在更严格的代码库中使用的规则。 (例如,此特定警告是 MISRA 中的错误。)
很多警告都是这样的...编译器编写者正在尝试检测程序行为意外或无意的情况,但警告不是总是正确的。例如,
uint64_t x = 0xffffffffu << 16;
在具有 32 位 int 的系统上,标准是非常清楚这个值应该是什么...应该是:
uint64_t x = 0xffff0000u;
但是,它 看起来 就像有人打算写这个:
uint64_t x = (uint64_t)0xffff0000 << 16;
这就是警告试图捕捉到的内容。这就是这条规则背后的推理。在你的情况下,编译器做得不好。
您可以在编译器文档中看到更详细的警告理由:Warning C26451。
幽灵与它无关。
完全没问题...
为此:
int a = value - 1;
found[a];
在这种情况下,“意图”更为明显,因为程序员已明确将“int”写为类型。
解决方案
这是一个代码风格问题,因此有几种不同的解决方案,您可以选择一个您觉得合适的解决方案。
保持警告开启(嘈杂,可能会分散您对真正警告的注意力)
首先将表达式分配给一个 int(详细)
禁用整个代码库的警告(如果您认为它没有帮助)
使用
禁用此位置周围的警告#pragma warning
(非常详细)