我正在开发一个传统的 32 位程序,其中有很多类型转换,例如DWORD* a = (DWORD*)b ,其中b是本机int ,我收到很多这样的警告: Cast to 'DWORD *' (aka 'unsigned int*') from smaller integer type 'int' ['c ...
提示:本站收集StackOverFlow近2千万问答,支持中英文搜索,鼠标放在语句上弹窗显示对应的参考中文或英文, 本站还提供 中文繁体 英文版本 中英对照 版本,有任何建议请联系yoyou2525@163.com。
我最近在我正在处理的项目中发现了一个很难找到的错误。 问题是我们做了一个有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 似乎没有等效的选择。
如果您希望在无符号算术中对溢出发出一致的警告,您需要围绕执行溢出检查的整数类型定义自己的包装类,例如,如果失败则抛出异常,或者您可以实现溢出安全加法/乘法的函数然后,您将不得不使用而不是+
和*
运算符。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.