UBA 清理器在 C++ 上将负双重命名为无符号长长的问题

Issue with UBA sanitizer casting negative double to unsigned long long on C++

提问人:Raz Cohen 提问时间:6/22/2023 最后编辑:Raz Cohen 更新时间:6/22/2023 访问量:90

问:

我一直在使用 C++,并一直在使用 UBA 清理器将双精度转换为无符号长整长。但是,当值为负数时,我遇到了一个问题,这会导致错误消息:“运行时错误:值 -2 超出了类型为'long long unsigned int'的可表示值范围”

代码是这样的:

unsigned long long valueULL = 0;
double value = -2;
valueULL = (unsigned long long)value;

我试图改用这个演员表,但它没有帮助:

valueULL = std::make_unsigned_t<unsigned long long>(value);

有没有办法在不遇到此错误的情况下强制转换它?

C++ Sanitizer 乌桑

评论

0赞 273K 6/22/2023
什么是UBA消毒剂?你能用一个通常的消毒剂名称吗?
0赞 Raz Cohen 6/22/2023
消毒剂是未定义的行为消毒剂 - UBSAN。
0赞 Peter 6/22/2023
您的描述不是特别清楚,但我认为有类型(和值)。将 a 转换为整型有两个步骤 - 首先,丢弃任何小数部分(截断为零)。从那里开始,如果无法使用整型表示截断的值,则行为是未定义的。这就是您的消毒剂检测到的内容(因为它超出了任何类型可以表示的范围)。至于你需要做什么 - 这取决于你期望转换为无符号类型会产生什么,而你根本没有描述过。valuedouble2.0double-2.0unsigned-2.0
0赞 273K 6/22/2023
你试过-2U吗?
1赞 harold 6/22/2023
可能只有一个合理的结果和建议的“两步铸造”,即会给你(unsigned long long)(long long)value

答:

1赞 Jan Schultke 6/22/2023 #1

看来你指的是 clang 的 UBSanitizer。 在这种情况下,清理程序是正确的,并且您的代码确实包含未定义的行为:-fsanitize=undefined

浮点类型的 prvalue 可以转换为整数类型的 prvalue。 转换被截断;也就是说,小数部分被丢弃。如果截断的值无法在目标类型中表示,则行为未定义。

- [conv.fpint] 第 1 节

您可以通过两步强制转换来修复未定义的行为:

double value = -2;
auto valueULL = static_cast<unsigned long long>(static_cast<long long>(value));

或者,您可以调用 std::llround:

auto valueULL = static_cast<unsigned long long>(std::llround(value));

注意:这将产生一个非常大的值,即 .如果这是您真正想要的,那么这些解决方案是有意义的。 否则,您应该听消毒剂的意见,并确保在转换为类型之前不会变成负数。ULLONG_MAX - 2doubleunsigned