【问题标题】:C++ How to check that a function is receiving an unsigned int?C ++如何检查函数是否正在接收无符号整数?
【发布时间】:2012-09-08 18:00:27
【问题描述】:

我有一个函数声明为:

void foo(unsigned int x)

如何检查 foo() 没有收到负数? 我希望如果我调用 foo(-1) 会引发异常, 但当然,由于 x 会自动转换为无符号,我无法检查它的积极性,例如:

if not(x>=0){ do_something();};

或类似的检查。

【问题讨论】:

  • 为什么不直接使用int
  • 如果foo 被传递一个隐式转换的int,比较以确保x <= std::numeric_limits<int>::max()
  • 但是如果我通过的正是最大数量呢?
  • 无法进行此项检查。但是,一个好的编译器会在看到需要在有符号和无符号之间转换的代码时发出警告。
  • @oldrinb 如果它被一个更大的 unsigned int 调用怎么办?基本上,没有办法区分显式使用的大数或负数转换产生的大数。

标签: c++ int unsigned


【解决方案1】:

确实没有什么好的方法,但你可以通过一些技巧来做到这一点:

1) 声明一个未定义的更好匹配:

void foo(unsigned int x) {
  //do something
}

void foo(int x);

2) 使用 typeid 来确定类型。

【讨论】:

  • 我喜欢 #2 的要点,使用 C++11 实用程序会变得更好。我确信this 并不完美,但它确实提供了一种可能性。
  • @chris 我也喜欢。另外,还有std::is_unsigned,可用于保持特定类型的整数(短与长等)的灵活性。
  • 你能扩展第 2 点吗? @jogojapan 那么标准库中有这样的功能吗?
  • @LucaCerone 如果您查看 chris 在 LiveWorkSpace 上准备的代码,您将了解如何使用模板和 static_assert 来避免从有符号到无符号的自动类型转换。我唯一建议的是,你可以直接使用std::is_unsigned<>,而不是std::is_same<>,像这样:liveworkspace.org/code/a7ec7f81b452ebf74acc73f990f79d9a# 优点是从unsigned short 等自动转换仍然可以工作,而signed 数据类型将不被接受。 (请注意,所有这些都在编译时起作用,而不是通过抛出运行时异常。)
【解决方案2】:

您定义了函数,因此它接受 unsigned int 参数,因此它不可能接收负值。

如果您使用int 参数调用它,则该值将从int 隐式转换为unsigned int,并且该转换的结果是明确定义的。这是该语言的一个特性,除非您的编译器碰巧为您提供了这样做的方法,否则您无法将其关闭——而且我不知道有哪个编译器可以这样做。

就你的函数而言,这两个调用:

foo(-1);       /* -1 is converted to unsigned int, to the value UINT_MAX */
foo(UINT_MAX);

无法区分。这不是唯一的情况。 任何负的int 值将被转换为有效的unsigned 值。

如果对于foo() 认为非常大的值无效,那么您可以检查参数值是否在某个“合理”范围内——但定义什么是“合理”并不总是那么容易。

【讨论】:

  • 我不认为这解决了问题,问题不在于 foo 是否可以处理 INT_MAXUINT_MAX 之间的数字,问题是如何在传递参数时出现编译器错误类型 int 而不是 unsigned int。
【解决方案3】:

我不是 C++ 专家,但是...

您只有固定数量的位(通常是 32 或 64)来表示一个整数。如果您知道永远不会有小于零的整数,则可以使用所有这些位并存储更大的数字。如果您的数字可能小于零,则编译器必须为符号保留一点。

比这要复杂一些 - 请参阅 Wikipedia article on 2's complement

长话短说,在 foo 中,如果您看到 x“非常非常大”,您可能被传递了一个负数。

检查您的编译器文档以了解 int 与 uint 的大小。

您可能希望将您的参数更改为常规整数 void foo(int x) 或者只是放松地知道在您当前的设置下 x 永远不会小于零。

【讨论】:

    【解决方案4】:

    正如 wich 的回答所暗示的,您可以添加一个带有 int 参数的 foo 的重载版本。既然你说你想让foo(-1) 抛出异常,你可以让重载的foo() 这样做:

    #include <iostream>
    
    class Wrong_Type {
    public:
        Wrong_Type(){}
    };
    
    void foo(unsigned n) {
        std::cout << "In foo, unsigned n = " << n << "\n";
    }
    
    void foo(int n) {
        std::cout << "In foo, int n = " << n << "\n";
        throw Wrong_Type();
    }
    
    int main() {
        try {
            foo(-1);
        }
        catch (Wrong_Type) {
            std::cout << "Caught Wrong_Type exception\n";
        }
    }
    

    当我运行它时,输出是:

    In foo, int n = -1
    Caught Wrong_Type exception
    

    但这不是一个理想的解决方案,因为它基于参数的type而不是它的值引发异常。 1-1 都是int 类型,所以调用foo(1) 也会抛出异常。并且一些其他有效的调用,例如foo(1.0),变得模棱两可。

    如果您可以将foo(1) 替换为foo(1U),其中1Uunsigned int 类型的常量,那么这可以工作。

    【讨论】:

      【解决方案5】:

      这是一个可能的解决方案:

      void foo(unsigned int x)
      {
        unsigned int last_bit_one = 1 << 31; 
        if ( (x & last_bit_one) != 0)           // check if the last bit of x is 1 
          std::cout << "NEGATIVE NUMBER" << std::endl;
        else
          std::cout << "do something" << std::endl;
      }
      

      当然,我们需要假设您输入的无符号数小于 2147483648。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-04-30
        • 2012-04-27
        • 1970-01-01
        • 2020-07-13
        • 1970-01-01
        • 1970-01-01
        • 2011-08-11
        • 1970-01-01
        相关资源
        最近更新 更多