正确地将有符号转换为无符号

时间:2019-01-28 14:42:58

标签: c++

我正在使用一个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 个答案:

答案 0 :(得分: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);
}

答案 1 :(得分:4)

如果您希望在运行时进行范围检查(即允许在 iff 类型之间进行转换,则可以保持所保存的值),Boost具有numeric_cast来实现。

如果您不想使用Boost,那么您的方法看起来还不错。

答案 2 :(得分:-1)

编辑:我想念您使用的是C ++,我以前的回答仅假定为C。

最简单,最标准的方法是使用

std::optional<unsigned int> index;

而不是使用-1或其他一些前哨值来表示无效索引。如果索引无效,则无需设置可选参数。然后您可以使用

进行查询
  

index.has_value()

找出它是否有效。