将枚举转换为具有溢出的整数时会出现警告
Posted
技术标签:
【中文标题】将枚举转换为具有溢出的整数时会出现警告【英文标题】:Expecting warnings when casting enums to integers with overflow 【发布时间】:2021-08-04 07:56:31 【问题描述】:我们有一个大型 C++ 项目,我们依靠编译器警告和 Flexelint 来识别潜在的编程错误。我很好奇一旦我们不小心尝试将枚举值转换为更窄的整数,他们会如何警告我们。
正如 Lint 所建议的,我们通常执行从枚举到整数的静态转换。 Lint 不喜欢隐式转换。我们通常会转换为方法所期望的确切类型。
我得到了有趣的结果,请看这个实验:
#include <iostream>
#include <string>
#include <stdint.h>
void foo(uint8_t arg)
std::cout << static_cast<int>(arg) << std::endl;
enum Numbers
hundred = 100,
thousand = 1000,
;
int main()
std::cout << "start" << std::endl;
foo(static_cast<uint8_t>(hundred)); // 1) no compiler or lint warning
foo(static_cast<uint8_t>(thousand)); // 2) no compiler or lint warning
foo(static_cast<int>(thousand)); // 3) compiler and lint warning
foo(thousand); // 4) compiler and lint warning
std::cout << "end" << std::endl;
http://cpp.sh/5hpyz
第一个案例无关紧要,只提好的案例。
有趣的是,在进行隐式转换时,我只在后两种情况下收到编译器警告。情况 2 中的显式转换将截断值(输出为 232,如下两个),但没有警告。好的,编译器可能假设我知道我在这里做什么,我的显式转换为uint8_t
。很公平。
我希望 Lint 能在这里帮助我。我在Gimpel's online Lint 中运行此代码,但也没有收到任何警告。仅在后两种情况下再次出现此警告:
warning 569: loss of information (call) in implicit conversion from 'int' 1000 (10 bits) to 'uint8_t' (aka 'unsigned char') (8 bits)
同样,在案例 2) 中显式转换为 uint8_t
,这会截断我的值,根本不会打扰 Lint。
假设枚举中的所有值都适合uint8_t
。但在某些未来,我们会添加更大的值(或者说:总共超过 256 个值),将它们强制转换,而不会注意到这会截断它们并得到意想不到的结果。
默认情况下,我总是转换为目标变量大小(案例 2))。鉴于这个实验,我想知道这是否是一种明智的方法。我应该转换为最广泛的类型并改用隐式转换(案例 3)吗?
获得预期警告的正确方法是什么?
【问题讨论】:
强制转换是告诉编译器“我知道我在做什么”的方式,因此它不会发出任何警告 【参考方案1】:你也可以写 foo(uint8_tthousand);
来代替 static_cast。这样,如果千位对于 uint8_t 来说太大,您将收到编译器错误/警告。但是不知道lint是怎么想的
【讨论】:
【参考方案2】:这是我也遇到的问题。我发现最好的方法是编写一个函数来为你执行强制转换,并且会在基于类型特征出现错误的情况下生成错误。
#include <type_traits>
#include <limits>
template<class TYPE>
TYPE safe_cast(const Numbers& number)
using FROM_TYPE = std::underlying_type_t<Numbers>;
// Might have to add some additional code here to fix signed unsigned comparisons.
if((abs(std::numeric_limits<TYPE>::min()) > static_cast<FROM_TYPE>(number)) ||
(std::numeric_limits<TYPE>::max() < static_cast<FROM_TYPE>(number)))
// Throw an error or assert.
std::cout << "Error in safe_cast" << std::endl;
return static_cast<TYPE>(number);
希望对你有帮助
附言如果你可以用 constexpr 重写它来编译时间,你也可以使用static_assert
。
【讨论】:
这样的检查范围很脆弱。例如,如果TYPE
和FROM_TYPE
的符号不同,那么它就会中断。 Use std::in_range
instead
@phuclv 没错,我没有时间也包含该代码,但确实包含了评论。以上是关于将枚举转换为具有溢出的整数时会出现警告的主要内容,如果未能解决你的问题,请参考以下文章