代码之家  ›  专栏  ›  技术社区  ›  Gamification

正确地将签名强制转换为未签名

c++
  •  3
  • Gamification  · 技术社区  · 6 年前

    我使用的是一个C库,它使用无符号整数作为某些数据的索引。但有时,函数返回这些带符号的索引,以便返回 -1 如果函数未能返回索引。*

    我如何预防 implicit conversion changes signedness 警告,如果无法转换,则引发运行时错误?您是否建议包装库函数以使用异常进行错误处理,并且只返回正确的值? 有没有一种标准的方法可以做到这一点:

    #include <stdlib.h>
    #include <errno.h>
    #include <limits.h>
    
    // pointless c function to demonstrate the question
    // parse the string to an unsigned integer, return -1 on failure
    int atoui(char const* str) {
        char* pend;
        long int li=strtol(str, &pend, 10);
        if ( errno!=0 || *pend!='\0' || li<0 || li>INT_MAX ) {
            return -1;
        } else {
            return li;
        }
    }
    
    // --8<---
    
    #include <stdexcept>
    
    // How to do this properly?
    unsigned int unsign(int i) {
        if(i<0) {
            throw std::runtime_error("Tried to cast negative int to unsigned int");
        } else {
            return static_cast<unsigned>(i);
        }
    }
    
    int main() {
        unsigned int j=unsign(atoui("42")); // OK
        unsigned int k=unsign(atoui("-7")); // Runtime error
    }
    
    3 回复  |  直到 6 年前
        1
  •  6
  •   Nicol Bolas    6 年前

    标准库没有这样的功能,但是编写这样的模板很容易:

    template<typename SInt, typename = std::enable_if_t<std::is_integeral_v<SInt> && std::is_signed_v<SInt>>>
    constexpr auto unsigned_cast(Sint i)
    {
      if(i < 0) throw std::domain_error("Outside of domain");
      return static_cast<std::make_unsigned_t<SInt>>(i);
    }
    

    您也可以返回 optional 如果您不喜欢为这些琐碎的事情抛出异常:

    template<typename SInt, typename = std::enable_if_t<std::is_integeral_v<SInt> && std::is_signed_v<SInt>>>
    constexpr std::optional<std::make_unsigned_t<SInt>> unsigned_cast_opt(Sint i)
    {
      if(i < 0) return std::nullopt;
      return static_cast<std::make_unsigned_t<SInt>>(i);
    }
    
        2
  •  4
  •   Lightness Races in Orbit    6 年前

    如果希望在运行时进行范围检查(即允许类型之间的转换 敌我识别 保持的值可以保持),Boost numeric_cast 这就实现了。

    如果你不想使用Boost,你的方法看起来就足够好了。

        3
  •  -1
  •   H. Al-Amri    6 年前

    编辑:我错过了你使用C++,我以前的答案只假设C。

    最简单和最标准的方法是

    std::optional<unsigned int> index;
    

    而不是使用-1或其他一些sentinel值来表示无效的索引。如果索引无效,则不设置可选的。然后你可以查询它

    index.has_value())

    找出它是否有效。