处理编译器关于可能丢失数据的警告的最优雅方法是什么
What's the most elegant way to handle the compiler warning about possible loss of data
在我们的大型C++项目中,我们努力没有警告,但人们往往对此很懒惰。 我不断修复的一件事是来自以下代码的警告:
sizex = sizey = 32 * c_scale;
给
警告 C4244:"=":从"双精度"转换为"i16",可能会丢失数据
其中 sizex 和 sizey 是 i16 型,c_scale 是双精度型。
所以我不断地将这样的代码行更改为类似
sizex = sizey = i16(32 * c_scale);
使警告消失。
我会说这会使代码的可读性降低,所以我对此并不满意,但在我看来,这比禁用警告要好,也比让一堆警告掩盖可能更严重的警告要好。
有人有更优雅或不同的方式来处理这种情况吗?
作为CppCoreGuidelines的一部分,有一个名为GSL的支持库。它们提供了一种安全的方式来转换类型,如下所示,称为narrow_cast:
它的标题可以在这里找到:https://github.com/Microsoft/GSL/blob/master/include/gsl/gsl_util
auto sizex = gsl::narrow<unsigned>(32 * c_scale);
这个想法是,如果结果类型(unsigned
这里(不够大(或有符号冲突(,将引发异常。
这是一个运行时检查。如果你想避免运行时检查的成本,你可以构造一个类似的函数,该函数仅在调试构建期间执行检查(当我们未定义时NDEBUG
并删除对发布版本的检查。
一些有用的可读性和可维护性指南:
使用标准类型
想象一下,我加入了你的项目。我不知道什么是i16
,你链接的任何库也不知道。但我确实知道什么是std::int16_t
(在<cstdint>
中找到(。图书馆作家也是如此。
隐藏抽象背后的细节
您在此处描述的操作是按某个因子(例如双精度?(缩放整数。细节决定成败。你不能在不丢失数据的情况下将双精度转换回整数,所以你必须恢复到一个转换,这看起来很混乱,会让未来的维护者想知道你在做什么。
因此,让我们构建一个抽象:
inline
auto scale_and_round_down(std::int16_t value, double scale) -> std::uint16_t
{
auto scaled_value = value * scale; // answer will be a double
return std::int16_t(value * scale); // round down to nearest int
}
现在我们的代码变成:
sizex = sizey = scale_and_round_down(32, c_scale);
毫无疑问地表达了意图。在发布版本中,scale_and_round_down
将是内联的。您无需为此类抽象支付任何性能成本。
我不知道你的i16
类型是什么,因为它不在 C++11 标准中。我猜你的意思是<cstdint>
中的ìnt16_t
类型,所以一个有符号的 16 位整数,并且你的sizex
和sizey
都是int16_t
类型。
你的c_scale
有些double
.所以可能是 IEEE754 64 位双精度浮点数。有关详细信息,请参阅 http://floating-point-gui.de/。它有一个53位的尾数。
您如何期望 53 位在 16 位中无损耗地适合(在所有情况下(?鸽子洞原则适用,并立即告诉您,由于 253大于 216,因此情况并非如此。
编译器给你一些警告是正确的。事实上,您可以显式设置一些强制转换以避免该警告
通过解释演员阵容,你只是告诉你的读者你知道这一点。可能,生成的机器代码在有或没有强制转换的情况下根本不会改变。
也许您的特定编译器可能还有其他方法来禁用该警告(可能是某些#pragma
(
您可以考虑使用一些更复杂的静态分析技术(可能是Frama-Clang(来进行更语义分析,并证明铸件不会泄漏精度。请注意,此类工具可能很难掌握!
顺便说一句,C++标准一般不会说明警告(它们是"实施质量"的事情(。您可以决定忽略它们(但实际上您不应该(。
- #define Dbg(fmt,..) (0) 是什么意思? 警告:表达式无效
- 处理编译器关于可能丢失数据的警告的最优雅方法是什么
- 警告的原因是什么:"when type is in parentheses, array cannot have dynamic size"?
- "警告:并非所有控制路径都返回值"是什么意思?(C++)
- 在C++中将已签名/未签名的警告静音的侵入性最小的方法是什么?
- 生成文件:此警告的名称是什么?
- 该C 警告是什么 - 控制达到非空隙函数的末端
- C++;编译过程中的警告"enabled by default"是什么意思?
- 这个链接器警告的含义是什么,以及如何修复它
- "universal-character-name encountered in source"警告的目的是什么?
- 在C++中使用-binary运算符从变量中去掉int时发出警告.原因是什么
- "padding class 'Tester' with 4 bytes"警告是什么意思?
- 有符号/无符号比较警告是什么意思
- 警告'RTTI symbol not found for class'是什么意思?
- C++'has virtual method ... but non-virtual destructor'编译期间警告是什么意思?
- 警告C4309 -它是什么意思,在这种情况下可以忽略它
- 警告C4247和C4248是什么意思,为什么从Visual c++ 2005中删除
- "potential divide by zero"在 Visual C++ C4723 警告说明中是什么意思?
- 使用 g++ 编译C++时,"隐藏构造函数"警告是什么意思?
- .crt部分?这个警告是什么意思