【问题标题】:c++ useless-cast from size_t to uint32_t for different targetsc++ useless-cast from size_t to uint32_t for different targets
【发布时间】:2021-06-03 09:13:25
【问题描述】:

我有一些针对不同目标构建的代码。它还有一些遗留函数使用 uint32_t 而不是 size_t - 当我想将 size_t 类型转换为它时,这很烦人 - 具有我们设置的警告级别(大量 gcc 警告)。

所以这是一个人为的例子:

val32 = static_cast<uint32_t>(strings.size());
val64 = static_cast<uint64_t>(strings.size());  // ERROR

根据运行在哪个拱上,上面两行之一将抱怨无用的强制转换警告(我们将其视为错误)。现在我知道有一些方法可以解决这个问题,将代码更改为 size_t ... 但是,这不是我的问题。我的问题是,当这种情况出现时,我怎样才能最好地解决这个问题。

我想出了一个解决方案 - 但它需要变量的引用传递:

template<typename TO, typename FROM>
TO static_cast_if_different(const FROM &value)
{
    if constexpr (std::is_same_v<TO, FROM>)
        return value;
    else
        return static_cast<TO>(value);
}

现在这行得通,但我觉得有更好的方法(也许内置在标准中 - 或者我在这里所做的改进)?

在此处查看完整的示例代码:https://godbolt.org/z/87hao1aTb

gcc 警告标志的完整列表:-Wall -Wextra -Wpedantic -Wconversion -Wsign-conversion -Wunreachable-code -Wlogical-op -Wshadow -Wmissing-include-dirs -Wparentheses -Wmisleading-indentation -Werror -Wno-psabi -Wno-error=deprecated-declarations -Wnon-virtual-dtor -Wuseless-cast -Wduplicated-cond -Wnull-dereference

注意:我不想删除 useless-cast 警告标志,因为它在其他地方很有用

【问题讨论】:

  • 这是一个很好的解决方案并且您可以添加一个断言,即不会丢弃任何有意义的位。
  • @n.1.8e9-where's-my-sharem。抱歉 - 我不明白那个断言部分,你能稍微解释一下吗?
  • 您可能只想处理整数类型,不是吗?
  • 您可以添加static_cast&lt;TO&gt;(value)==value。顺便说一句,您甚至不需要演员表或if (std::is_same_v...)TO result = value; 也可以正常工作(在无符号类型的情况下)。通过 const ref 或通过 value 无关紧要,无论如何它都会被内联并完全优化掉。
  • 我的意思是,assert(static_cast&lt;TO&gt;(value)==value)

标签: c++ gcc static-cast


【解决方案1】:

这是一个很好的解决方案,它仍然可以有所改进。

  1. 演员表和std::is_same_v 并不是真正需要的。一个简单的赋值将做完全相同的事情(当使用 unsigned 整数类型时,但我们想检查一下)。该函数可能如下所示:

     template<typename TO, typename FROM>
     TO legacy_size_cast(FROM value)
     {
        static_assert(std::is_unsigned_v<FROM> && std::is_unsigned_v<TO>,
                      "Only unsigned types can be cast here!");
        TO result = value;
        return result;
     }
    

    您仍然会在调用站点上看到类型转换的视觉指示,我想这就是您所追求的。但如果您出于某种原因确实需要实际演员表,您仍然可以添加它:

     TO result = static_cast<TO>(value);
    
  2. 您可以通过添加以下内容来防止意外溢出:

     assert(result == value);
    

    这可能看起来不是非常有用(谁将分配一个 4GB 对象?)但实际上它可以在传递负偏移量时捕获令人讨厌的错误,例如(uint64_t)(-1)。这实际上是一个巨大的正值,但它在算术上的行为类似于-1...直到你将它转换为uint32_t,然后再转换回uint64_t,然后它突然不会了,assert 会抓住那个。

  3. 通过引用或值传递都没有关系。在发布版本中,无论如何都将完全内联和优化该函数。

【讨论】:

    【解决方案2】:

    我建议使用宏。 例如

    #ifdef SOME_ARCH
    code
    #else
    other code
    #endif
    

    然后当你为 some_arch 编译时,将-D SOME_ARCH 添加到编译标志中。

    【讨论】:

      猜你喜欢
      • 2022-10-04
      • 1970-01-01
      • 2021-05-06
      • 2022-12-26
      • 1970-01-01
      • 2022-12-27
      • 2022-11-20
      • 2020-06-05
      • 1970-01-01
      相关资源
      最近更新 更多