【问题标题】:Prevent user passing negative numbers to a function accepting unsigned int防止用户将负数传递给接受 unsigned int 的函数
【发布时间】:2013-09-05 15:56:06
【问题描述】:

代码如下:

int create_mask(unsigned b, unsigned e)
{
  unsigned int mask=1;

  if(b<e || b<0 || e<0)
  {
    printf("Wrong values, starting bit can't be smaller than ending.\n");
    printf("Both got to be >= 0.\n");
    exit(EXIT_FAILURE);
  }
  while(b>0)
  {
    printf("%u\n", b);
    mask<<=1;
    if(b>e)
      mask|=1;
    b--;
  }

  return ~mask; /* negates mask for later purpose that is clearing corresponding bits */
}

函数为某些位操作创建掩码,但应采用两个无符号整数 b 和 e,均为非负数。问题是如何防止用户输入负数? 当使用 (-1,0) 调用函数时,它会启动循环,并应退出并出现错误。

【问题讨论】:

  • 但是无符号数永远不会是负数,这是什么意思呢?
  • 首先,不要让函数被(-1, 0) 调用。输入一个字符串,然后使用strtoul() 将其转换为无符号整数。如果数字为负数会报错。
  • @harold 发生从有符号到无符号的隐式转换,它以 1 &lt;&lt; width 为模进行解释,其中 widthunsigned int 中的位数。
  • 有符号整数 -1,当解释为无符号整数时,将等于最大值。所以它不小于e,或者小于0。
  • @Taemyr 不一定,仅当机器使用 2 的补码表示负数时。

标签: c negative-number unsigned-integer


【解决方案1】:

您可以只输入一个字符串,检查它是否包含'-' 字符,如果包含则产生错误。否则,您将其转换为无符号整数并继续。 (无论如何,作为字符串读取然后使用strtoul() 转换比使用scanf() 更可取,尤其是当您不了解scanf() 的所有怪癖时。)

char buf[LINE_MAX];
fgets(buf, sizeof buf, stdin);

if (strchr(buf, '-') != NULL) {
    fprintf(stderr, "input must be non-negative!\n");
    exit(-1);
}

unsigned int n = strtoul(buf, NULL, 0);

【讨论】:

  • sscanf(buf, "%lu", &amp;n); 也会进行转换,但我认为strtoul 更好:)
  • @boleto 我使用(并建议)使用strtoul()而不是scanf()并不是巧合。
  • 如果您要重新设计界面,那么指定 int 而不是 string 似乎更明智。然后,如果值为
【解决方案2】:

编辑:

您可以使用long int 输入,然后检查输入是否在0 to ending range of unsigned int 之间。如果是这样,则分配给您的变量,否则会向用户抛出异常,您应该只提供无符号数字作为输入。

long int input;
unsigned int valid_input;

scanf("%ld",&input);
if((0<= input) && (input <= 4294967295))
valid_input= (unsigned int)input  ;
else
printf("Unvalid input\n");

正如 H2CO3 所说。 将输入读入字符串并检查第一个文字,如果它不是负数,则转换为无符号整数将比下面的方法更可取。因为一半的无符号整数部分没有被覆盖。

您可以将输入输入int,然后如果它是非负数,则继续。如果它是负数,则向用户提出异常,您不应该给出负数输入。

【讨论】:

  • 但这将使得无法使用某些高无符号值(当发生从unsignedsigned 的转换时,这将溢出到int 范围的负半部分。并且有符号无论如何,整数溢出都是未定义的行为,因此这不可能是正确的解决方案。)
  • 没错,这就是问题所在。
  • @zubergu 同样,请参阅我对您问题的第一条评论。
  • @zubergu 但是这些数字实际上根据定义等于负数。 - 因此,当您要求排除负数时,您在某种意义上也要求排除高无符号整数。
  • @Gangadhar 好吧,scanf() 在遇到负数时不会退出。它将扫描一个有符号整数,然后将其转换为无符号整数,并报告成功。
【解决方案3】:

看看这个:Stopping function implicit conversion

我能够根据您的问题对其进行调整,并且它会阻止程序链接。上述线程中的信息似乎部分不正确,因为示例编译得很好。它无法链接,因为没有定义模板特化。实际上,我对以下适用于 int 与 unsigned int 的情况感到有些惊讶。

template <class T>
void foo(const T& t);

template <>
void foo<unsigned int>(const unsigned int& t)
{

}

int main(){
  foo((unsigned int) 9); // will compile and link
  unsigned int value(5);
  foo(value);// will compile and link
  foo(9.0); // will not link
  foo(-9); // will not link
  return 0;
}

我认为你可能想多了。真的有问题吗?让您的 id 类型以 int 开头会更好吗?是否有一个最小/最大 id 可以避免可能被误认为是双恭维的大数字?这似乎是语言的一个不幸问题,它没有提供任何简单的方法来停止隐式强制转换。

我使用 Visual Studio 2010 测试了该示例。此外,我没有时间编写测试类,因此如果您对它感兴趣,那么您必须将该示例改编为 foo 类以查看它是否适用类的构造函数,或者如果有另一种使用模板的方法来执行此操作。根据其他答案和我的经验,我认为您不会找到一种简单的方法来做您想做的事。

【讨论】:

  • 感谢您的回答,但问题标记为 C,严格来说是 C。
猜你喜欢
  • 2019-10-07
  • 1970-01-01
  • 1970-01-01
  • 2020-02-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多