gpt4 book ai didi

C++ 在 64 位变量中存储 32 位值时发出警告

转载 作者:行者123 更新时间:2023-12-05 05:38:56 24 4
gpt4 key购买 nike

我最近在我从事的项目中发现了一个很难找到的错误。问题是我们进行的计算有一个 uint32_t 结果,并将其存储在一个 uint64_t 变量中。我们期望结果是 uint64_t,因为我们知道结果对于 32 位无符号整数来说可能太大了。

我的问题是:有没有办法让编译器(或像 clang-tidy 这样的静态分析工具)在发生这种情况时警告我?

一个例子:

#include <iostream>

constexpr uint64_t MUL64 { 0x00000000ffffffff };
constexpr uint32_t MUL32 { 0xffffffff };

int main() {
const uint32_t value { 0xabababab };

const uint64_t value1 { MUL64 * value }; // the result is a uint64_t because
// MUL64 is a uint64_t
const uint64_t value2 { MUL32 * value }; // i'd like to have a warning here

if (value1 == value2) {
std::cout << "Looks good!\n";
return EXIT_SUCCESS;
}
std::cout << "Whoopsie\n";
return EXIT_FAILURE;
}

编辑:

溢出是预料之中的,即我们知道我们需要一个 uint64_t 来存储计算值。我们也知道如何解决这个问题,后来我们将其更改为:

const uint64_t value2 { static_cast<uint64_t>(MUL32) * value };

这样高 32 位不会在计算过程中被截断。但是这样的事情还是时有发生,我就想知道有没有办法检测到这种错误。

提前致谢!

你好,
塞巴斯蒂安

最佳答案

无符号整数类型的乘法行为被明确定义为围绕模 2 整数类型宽度的幂。因此这里没有任何编译器可以警告的内容。该行为是预期的并且可能是故意的。警告它会产生太多误报。

此外,通常编译器无法在常量表达式计算之外的编译时测试溢出。在这种特定情况下,这些值非常明显,因此它可以做到这一点。

关于算术后任何扩大转换的警告也很可能非常嘈杂。

由于上述原因,我不知道有任何编译器标志会添加警告。


Clang-tidy 确实有一个名为 bugprone-implicit-widening-of-multiplication-result 的支票专门针对这种以较窄类型执行乘法的情况,然后隐式加宽。似乎自 LLVM 13 以来就存在检查。不过我认为没有等效的添加。

此检查在这里按预期工作:

<source>:11:29: warning: performing an implicit widening conversion to type 'const uint64_t' (aka 'const unsigned long') of a multiplication performed in type 'unsigned int' [bugprone-implicit-widening-of-multiplication-result]
const uint64_t value2 { MUL32 * value }; // i'd like to have a warning here
^
<source>:11:29: note: make conversion explicit to silence this warning
const uint64_t value2 { MUL32 * value }; // i'd like to have a warning here
^~~~~~~~~~~~~
static_cast<const uint64_t>( )
<source>:11:29: note: perform multiplication in a wider type
const uint64_t value2 { MUL32 * value }; // i'd like to have a warning here
^~~~~
static_cast<const uint64_t>()

Clang 的未定义行为清理器还检查在运行时标记所有 无符号整数溢出,这通常不包含在 -fsanitize=undefined 中。它可以包含在 -fsanitize=unsigned-integer-overflow 中。这很可能需要为预期的环绕行为添加抑制。参见 https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html了解详情。

然而,由于算术是由编译器在编译时执行的,因此这里似乎没有应用此检查。如果您删除 value2 上的 const,UBSan 会捕获它:

/app/example.cpp:11:29: runtime error: unsigned integer overflow: 4294967295 * 2880154539 cannot be represented in type 'unsigned int'
SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior /app/example.cpp:11:29 in
Whoopsie

GCC 似乎没有等效的选项。


如果你想要一致的无符号算术溢出警告,你需要围绕执行溢出检查的整数类型定义你自己的包装类,例如如果失败则抛出异常,或者您可以实现溢出安全的加法/乘法函数,然后您必须使用这些函数来代替 +* 运算符。

关于C++ 在 64 位变量中存储 32 位值时发出警告,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/72813805/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com