【问题标题】:How can I capture an unsigned value without casting?如何在不强制转换的情况下捕获无符号值?
【发布时间】:2019-07-23 21:04:45
【问题描述】:

如何在不强制转换的情况下捕获 unsigned 值?

我正在编写一个简单的程序来计算一个数字数组的 LCF 和 GCD。为了正确计算它们,数字应始终为正整数,因为我选择了“unsigned long long int”类型。但是,我仍然没有找到阻止用户输入负值不进行强制转换的方法。

每当我使用std::cin >> variable 时,程序都允许用户输入一个负数。在无符号值的情况下,数字将是类型大小的范围减值。在unsigned short整数的情况下,如果用户输入-5,则存储在变量中的值将是65.531

这是我正在尝试改进的代码部分:

#include<iostream>
#include<stdlib.h>
using namespace std;

typedef unsigned long long int ulli;

 /* many lines of code, variables already declared */

// array_list_of_numbers is of type UNsigned long long int
// var_verify_if_negative is of type signed long long int

    cout << "Please inform the numbers." << endl;
    for ( iterador1 = 0 ; iterador1 < size_of_the_list ; ++iterador1){
        cout << "Please, inform  number  "<< iterador1+1 << ": ";
        cin >> var_verify_if_negative;
        while (var_verify_if_negative <= 0){
            cout << "Number must be equal or greater than 1!" << endl;
            cout << "Try again: ";
            cin >> var_verify_if_negative;  
        /*end while*/}
        array_list_of_numbers[iterador1] = (ulli)var_verify_if_negative; // << here is the casting 
    /*end for*/}

但是,如果我使用有符号变量的转换,则根本没有使用无符号数据类型的意义。最好将变量声明为已签名并执行检查。

原来的代码是:

cout << "Please inform the numbers." << endl;
    for ( iterador1 = 0 ; iterador1 < size_of_the_list ; ++iterador1){
        cout << "Please, inform  number  "<< iterador1+1 << ": ";
        cin >>  array_list_of_numbers[iterador1];
    /*end for*/}

允许错误输入。 如何测试用户是否使用 std::cin 输入了签名值?

【问题讨论】:

  • 不要使用无符号类型。仅仅因为数字不能为负并不意味着您应该使用无符号类型。对位操作使用无符号,对其他一切使用有符号,除非你真的需要那个额外的位。如果你使用有符号类型,那么检查你是否得到一个负数是微不足道的。

标签: c++ types casting signed


【解决方案1】:

为什么不简单地阅读一个(签名的)long并在它是否定的时候拒绝它并在其他情况下使用它?

如果您确实需要 unsigned long 的全部范围,您需要先读取一个字符串,检查它是否以“-”开头(并拒绝),否则转换为 unsigned long。

【讨论】:

  • 这个想法是使用全范围的 unsigned LLI 。您使用字符串的想法似乎是解决此问题的正确方法,即使非常大的数字也会在程序中造成错误。
【解决方案2】:

不幸的是,没有特定的提取器会拒绝标准流的有符号整数,而是将有符号整数转换为无符号值(这实际上是负数的未定义行为)。

但是,您的整个方法有些缺陷。如果你想禁止小于 0 的数字,你能做的最好的就是实际接受有符号整数,然后检查数字是否大于零并在不大于零时报告错误(并拒绝输入)。

【讨论】:

    【解决方案3】:

    当预期类型是无符号类型时输入负数时,流提取器报告失败的最佳情况是。

    unsigned int num;
    while ( !(in >> num) )
    {
       std::cerr << "Wrong input. Try again...";
    }   
    

    但是,标准规定即使预期类型是无符号类型,也可以输入负数。

    当类型为无符号类型时,标准库在核心转换逻辑中使用%u 格式说明符。来自https://en.cppreference.com/w/cpp/locale/num_get/get

    如果v的类型是无符号的,将使用转换说明符%u

    现在,如果你看一下标准库是如何处理%u (https://en.cppreference.com/w/cpp/io/c/fscanf#Parameters) 的,转换是由strtoul 执行的。

    来自strtoul documentation

    如果减号是输入序列的一部分,则从数字序列计算的数值会被取反,就像结果类型中的一元减号一样,它应用无符号整数环绕规则。

    最好的办法是读入有符号类型并确保它是非负数,然后再继续使用它。

    【讨论】:

      猜你喜欢
      • 2018-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-05-23
      • 2020-08-08
      • 2014-09-27
      • 1970-01-01
      • 2020-09-19
      • 1970-01-01
      相关资源
      最近更新 更多