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

How can I capture an unsigned value without casting?

如何在不转换的情况下捕获一个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 输入了带符号的值?

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

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

为什么不简单地读取一个(有符号的)long 并在它为负时拒绝它并在其他情况下使用它?

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

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

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

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

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

If the type of v is unsigned, will use conversion specifier %u

现在,如果您查看标准库如何处理 %u (https://en.cppreference.com/w/cpp/io/c/fscanf#Parameters),转换是由 strtoul.

执行的

来自strtoul documentation

If the minus sign was part of the input sequence, the numeric value calculated from the sequence of digits is negated as if by unary minus in the result type, which applies unsigned integer wraparound rules.

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