Каков эффективный способ избежать целочисленного переполнения при преобразовании беззнакового целого числа в целое число в С++?

Является ли следующий эффективный и беспроблемный способ преобразования беззнакового целого числа в целое число в С++:

#include <limits.h>
void safeConvert(unsigned int passed) 
{
    int variable = static_cast<int>(passed % (INT_MAX+1)); 
    ...
}

Или есть лучший способ?

ОБНОВЛЕНИЕ

Как указал Джеймс Макнеллис, присваивание unsigned int > INT_MAX целому числу не является неопределенностью — скорее, это определяется реализацией. Таким образом, контекст здесь теперь конкретно зависит от моего предпочтения, чтобы гарантировать, что это целое число сбрасывается до нуля, когда беззнаковое целое превышает INT_MAX.

Исходный контекст

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

При нормальной работе эти счетчики останутся в пределах INT_MAX. Однако, чтобы не столкнуться со специфическим поведением реализации undefined в случае возникновения ненормального (но действительного) случая, я хочу, чтобы здесь было какое-то эффективное преобразование.


person Glen T    schedule 02.03.2011    source источник
comment
Должно быть safeConvert? Итак, что вы хотите, чтобы произошло, когда ввод больше, чем INT_MAX? Вы хотите, чтобы в этом случае был установлен какой-то флаг?   -  person Hamish Grubijan    schedule 02.03.2011
comment
В то время как переполнение во время арифметических операций со знаком приводит к неопределенному поведению, преобразование в целочисленный тип со знаком — нет: результаты определяются реализацией, если значение не может быть представлено целевым типом.   -  person James McNellis    schedule 02.03.2011
comment
@Hamish Спасибо за опечатку. Когда вход больше, чем INT_MAX, обеспечение значения int > 0 предпочтительнее.   -  person Glen T    schedule 02.03.2011
comment
@James Хороший вопрос, так что технически задание действительно без какой-либо санитарии. Таким образом, вопрос здесь больше о том, что я предпочитаю значение, когда произойдет переполнение?   -  person Glen T    schedule 02.03.2011
comment
Я бы использовал if, но это только я, я думаю   -  person Nate Koppenhaver    schedule 02.03.2011


Ответы (2)


Это также должно работать:

int variable = passed & INT_MAX;
person Ben Voigt    schedule 02.03.2011
comment
@Jerry: обычно я считаю, что писать код быстрее, чем объяснение. Просто код стал плотнее и лаконичнее, а скорость набора текста несколько ограничивает, по крайней мере, для меня. - person Ben Voigt; 02.03.2011
comment
Это решение, хотя и аккуратное, использует зависящее от реализации свойство INT_MAX (которое обычно определяется как 2**n - 1). В частности, цель ОП заключалась в том, чтобы избежать поведения, определяемого реализацией. Лучше всего проверять это свойство с помощью чего-то вроде typedef char Test[((INT_MAX + 1u) & ((INT_MAX + 1u) - 1)) == 0]; first ;) - person decltype; 02.03.2011
comment
@decltype: я думаю, что это свойство универсально верно. Но я это учитывал. Эта формула отображает каждое целое число в диапазоне (0..INT_MAX), независимо от того, является ли INT_MAX+1 степенью числа 2. - person Ben Voigt; 02.03.2011
comment
Это пример кода, который я не считаю самодокументируемым (существуют большие дебаты о том, бесполезны ли комментарии). - person Hamish Grubijan; 02.03.2011
comment
@ Хэмиш: Верно. Мы ожидаем, что те, кто использует код, сделают немного больше, чем просто вырезают и вставляют его в свой проект. Они должны добавлять комментарии, исправлять имена переменных, настраивать стиль и делать все остальное, что необходимо для удовлетворения требований их проекта. И если они не понимают этого достаточно хорошо, чтобы написать эту документацию, они могут оставить здесь комментарий и спросить. - person Ben Voigt; 02.03.2011
comment
@ Бен, если человек не понимает код, ему не следует трогать C. - person bestsss; 06.03.2011

При нормальной работе эти счетчики останутся в пределах INT_MAX. Однако, чтобы избежать неопределенного поведения в случае возникновения ненормального (но допустимого) случая, я хочу, чтобы здесь было какое-то эффективное преобразование.

Эффективное преобразование во что? Если все общие значения для int и unsigned int совпадают, и вы хотите, чтобы другие значения без знака, такие как INT_MAX + 1, имели различные значения, то вы можете сопоставить их только с отрицательными целыми значениями. Это делается по умолчанию и может быть явно запрошено с помощью static_cast<int>(my_unsigned). В противном случае вы можете сопоставить их все с 0, или -1, или INT_MIN, или отбросить старший бит... самый простой способ: if (my_unsigned > INT_MAX) my_unsigned = XXX или ...my_unsigned &= INT_MAX для очистки старшего бита. Но будут ли вызванные функции работать правильно, если int переполнится? Возможно, лучшим решением было бы использовать для начала 64-битные целые числа?

person Tony Delroy    schedule 02.03.2011