如何在不进行强制转换的情况下捕获未签名的值?

时间:2019-03-01 19:39:09

标签: c++ types casting signed

如何捕获一个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输入了签名值?

3 个答案:

答案 0 :(得分:1)

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

但是,您的整个方法还是有缺陷的。如果您要禁止小于0的数字,最好的办法是实际接受带符号的整数,然后检查该数字是否大于零并在不大于0的情况下报告错误(并拒绝输入)。

答案 1 :(得分:1)

为什么不简单地读一个(带符号的)long并在它为负数时拒绝它,否则使用它呢?

如果您确实需要完整的无符号长整数,则需要首先读取一个字符串,检查它是否以'-'开头(并拒绝),否则转换为无符号长整数。

答案 2 :(得分:1)

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

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

现在,如果您查看标准库如何处理%uhttps://en.cppreference.com/w/cpp/io/c/fscanf#Parameters),将由strtoul执行转换。

来自strtoul documentation

  

如果减号是输入序列的一部分,则从数字序列计算出的数值将被否定,就好像结果类型中的一元减号一样,这将应用无符号整数环绕规则。

您最好的选择是读入带符号的类型,并确保它是一个非负数,然后再使用它。