Как я могу получить значение без знака без приведения? - PullRequest
0 голосов
/ 01 марта 2019

Как я могу захватить значение unsigned без приведения?

Я пишу простую программу для вычисления LCF и GCD из массива чисел.Чтобы правильно рассчитать их, числа должны быть всегда положительными интергерсами, для которых я выбрал тип "unsigned long long int".Однако я до сих пор не нашел способа запретить пользователю вводить отрицательное значение без приведения.

Всякий раз, когда я использую std::cin >> variable, программа позволяет пользователю вводить отрицательное число,В случае значений без знака число будет значением диапазона минус значения размера.В случае unsigned short interger, если пользователь вводит -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 голосов
/ 01 марта 2019

Почему бы просто не прочитать длинную (подписанную) и отказаться от нее, когда она отрицательна, и использовать ее иначе?

Если вам действительно нужен полный диапазон длин без знака, вам нужно сначала прочитать строку, проверить, начинается ли она с «-» (и отказаться), и в противном случае преобразовать в длину без знака.

0 голосов
/ 01 марта 2019

В лучшем случае сценарий извлечения потока мог бы сообщить о сбое при вводе отрицательного числа, когда ожидаемый тип является беззнаковым типом.

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 документация :

Если минусзнак был частью входной последовательности, числовое значение, вычисленное из последовательности цифр, сводится на нет, как если бы унарный минус в типе результата, который применяет правила целочисленного округления без знака.

Лучше всего ставитьпрочитайте подписанный тип и убедитесь, что это неотрицательное число, прежде чем использовать его.

0 голосов
/ 01 марта 2019

К сожалению, не существует специального экстрактора, который бы отказывался от целых чисел со знаком для стандартного потока, вместо этого целое число со знаком преобразуется в значение без знака (что фактически является неопределенным поведением для отрицательных чисел).

Однако весь ваш подходнесколько ошибочно.Если вы хотите запретить числа, которые меньше 0, лучшее, что вы можете сделать, - это на самом деле принять целые числа со знаком, а затем проверить, что число больше нуля, и сообщить об ошибке (и отклонить ввод), если это не так.

...