На днях Я столкнулся с этой конструкцией:
static_cast<size_type>(-1)
в некотором примере кода на С++, который, скорее всего, (в зависимости от того, где находится size_type
), эквивалентен следующему C:
(size_t)(-1)
Как я понимаю, он работает на основе того, что представление -1 в двухпараметрической арифметике - это 11111...1
, для такого количества бит, как у вас, так что это быстрый способ получить максимальное значение, которое неподписанный тип типа size_t
может иметь место. Тем не менее, я понимаю, что C не гарантирует, что будет использоваться двойной набор; если реализация C использует одно дополнение, это будет на 1 меньше максимального значения, и если он использует значение знака, оно будет чуть более половины максимального значения.
Есть ли какая-то морщина, которую мне не хватает, что гарантирует, что это работает правильно, независимо от того, используется ли выражение целых чисел? Различия между C и С++ (многие удивительные вещи)?
Ответ 1
Требования к беззнаковой арифметике гарантируют, что приведение -1 к неподписанному типу приведет к наибольшему числу возможных для целевого типа. C99, §6.2.5/9: "... результат, который не может быть представлен результирующим беззнаковым целочисленным типом, уменьшается по модулю по числу, которое больше, чем наибольшее значение, которое может быть представлено результирующим типом".
Это то же самое в C и С++ (в стандарте С++ аналогичная формулировка содержится в сноске 41 - она не является нормативной, но объясняет другую формулировку).
Ответ 2
Чтобы быть на "безопасной" стороне и делать это "правильно" (С++), стоит посмотреть на STL:
std::numeric_limits<size_t>::max()
Ответ 3
"Как я понимаю, он работает, основываясь на том, что представление -1 в двойной арифметике дополняет...".
Нет, это не основано на этом факте. Он основан на стандартном требовании, что записанные значения, преобразованные в N-разрядный неподписанный тип, должны приводить к значению без знака, которое "равно" оригиналу, подписанному по модулю 2 ^ N.
Он должен работать таким образом, независимо от подписанного представления, используемого в реализации. В случае 2 дополнения он работает таким образом сам по себе, но для других представлений компилятору придется выполнить дополнительную работу, чтобы удовлетворить стандартное требование.
Ответ 4
Если вы хотите получить максимальное (или минимальное) значение определенного типа переносимым способом, лучше всего использовать стандартный класс numeric_limits
следующим образом.
#include <limits>
size_type max = std::numeric_limits<size_type>::max()
size_type min = std::numeric_limits<size_type>::min()
Я подозреваю, что некоторые реализации этих функций могут использовать листинг, который вы описываете как оптимальный для платформы способ получить минимальный/максимальный.