将枚举转换为具有溢出的整数时会出现警告

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

【讨论】:

这样的检查范围很脆弱。例如,如果TYPEFROM_TYPE 的符号不同,那么它就会中断。 Use std::in_range instead @phuclv 没错,我没有时间也包含该代码,但确实包含了评论。

以上是关于将枚举转换为具有溢出的整数时会出现警告的主要内容,如果未能解决你的问题,请参考以下文章

警告 C26451:算术溢出(减去两个整数时)

将枚举类型传递给具有整数值的转换器[重复]

C++ 指针警告:算术溢出:对 4 字节值使用运算符“-”,然后将结果转换为 8 字节值

c#下可否将一个枚举类型的数组转换为一个整型数组

如何将字符串转换为枚举值到整数? [复制]

Django/Python:如何将整数转换为等效的枚举字符串? [复制]