Подтвердить что ты не робот

Правильно ли `-1` для использования в качестве максимального значения целого числа без знака?

Есть ли какой-либо стандартный параграф С++, в котором говорится, что использование -1 для этого является переносимым и правильным способом или единственный способ сделать это правильно - использовать предопределенные значения?

У меня был разговор с моим коллегой, что лучше: используя -1 для максимального целого числа без знака или используя значение от limits.h или std::numeric_limits?

Я сказал своему коллеге, что использование предопределенных максимальных значений из limits.h или std::numeric_limits является переносным и чистым способом сделать это, однако, коллега возражал против -1, будучи таким же переносимым, как числовые ограничения, и больше, у него есть еще одно преимущество:

unsigned short i = -1; // unsigned short max

можно легко изменить на любой другой тип, например

unsigned long i = -1; // unsigned long max

при использовании предопределенного значения из заголовочного файла limits.h или std::numeric_limits также требуется переписать его вместе с типом слева.

4b9b3361

Ответ 1

Не использовать стандартный способ или не показывать четко намерение часто плохой идеей, что мы платим позже

Я бы предложил:

auto i = std::numeric_limits<unsigned int>::max(); 

или @jamesdin предложили конечно лучший, ближе к C привычки:

unsigned int i = std::numeric_limits<decltype(i)>::max(); 

Ваш аргумент коллеги недопустим. Изменение intlong int, как показано ниже:

auto i = std::numeric_limits<unsigned long int>::max(); 
  • не требует дополнительной работы по сравнению с решением -1 (благодаря использованию auto).
  • "-1" решение прямо не отражает наше намерение, следовательно, оно может иметь вредные последствия. Рассмотрим этот фрагмент кода:

.

using index_t = unsigned int;

... now in another file (or far away from the previous line) ...

const index_t max_index = -1;

Во-первых, мы не понимаем, почему max_index есть -1. Хуже, если кто-то хочет улучшить код и определить

 using index_t = ptrdiff_t;

= > , тогда оператор max_index=-1 больше не является max, и вы получите багги-код. Снова это не может произойти с чем-то вроде:

const index_t max_index = std::numeric_limits<index_t>::max();

CAVEAT:, однако при использовании std::numeric_limits существует оговорка. Он не имеет ничего общего с целыми числами, но связан с числами с плавающей запятой.

std::cout << "\ndouble lowest: "
          << std::numeric_limits<double>::lowest()
          << "\ndouble min   : "
          << std::numeric_limits<double>::min() << '\n';

печатает:

double lowest: -1.79769e+308    
double min   :  2.22507e-308  <-- maybe you expected -1.79769e+308 here!
  • min возвращает наименьшее конечное значение данного типа
  • lowest возвращает наименьшее конечное значение данного типа

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

Ответ 2

Что касается преобразований целых чисел, C 2011 [проект N1570] 6.3.1.3 2 говорит

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

Таким образом, преобразование -1 в целое число без знака обязательно порождает максимальное значение этого типа.

Могут возникнуть проблемы с использованием -1 в различных контекстах, где он не сразу преобразуется в нужный тип. Если он немедленно преобразуется в нужный целочисленный тип без знака, как при назначении или явном преобразовании, результат становится ясным. Однако, если это часть выражения, его тип int, и он будет вести себя как int до конвертирования. Напротив, UINT_MAX имеет тип unsigned int, поэтому он ведет себя как unsigned int.

Как chux указывает в комментарии, USHRT_MAX эффективно имеет тип int, поэтому даже именованные ограничения не полностью безопасны от типа вопросы.

Ответ 3

Правильно ли использовать -1 в качестве максимального значения целого числа без знака?

Да, это функционально правильно, когда используется как прямое назначение/инициализация. Все же часто выглядит сомнительным @Ron.

Константы из limits.h или std::numeric_limits более глубокое понимание кода, но нуждаются в обслуживании в случае изменения типа i.


[Примечание] OP позже удалите тег C.

Чтобы добавить альтернативу присвоению максимального значения (доступно в C11), которая помогает сократить обслуживание кода:

Используйте любимый/ненавистный _Generic

#define info_max(X) _Generic((X), \
  long double: LDBL_MAX, \
  double: DBL_MAX, \
  float: FLT_MAX, \
  unsigned long long: ULLONG_MAX, \
  long long: LLONG_MAX, \
  unsigned long: ULONG_MAX, \
  long: LONG_MAX, \
  unsigned: UINT_MAX, \
  int: INT_MAX, \
  unsigned short: USHRT_MAX, \
  short: SHRT_MAX, \
  unsigned char: UCHAR_MAX, \
  signed char: SCHAR_MAX, \
  char: CHAR_MAX, \
  _Bool: 1, \
  default: 1/0 \
  )

int main() {
  ...
  some_basic_type i = info_max(i);
  ...
}

Приведенный выше макрос info_max() имеет ограничения, касающиеся таких типов, как size_t, intmax_t и т.д., intmax_t могут не быть перечислены в приведенном выше списке. Есть более сложные макросы, которые могут справиться с этим. Идея здесь является иллюстративной.

Ответ 4

Техническая сторона была покрыта другими ответами; и в то время как вы фокусируетесь на технической правильности в своем вопросе, важно отметить, что вопрос чистоты снова важен, потому что imo - это гораздо более важный момент.

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

Im фактически немного озадачил, что кто-то даже рассмотрит этот трюк всерьез. Theres однозначный, интуитивно понятный и идиоматический способ установить значение его max в C: макросы _MAX. И theres дополнительный, одинаково однозначный, интуитивно понятный и идиоматический способ в С++, который обеспечивает еще больше безопасности типов: numeric_limits. Этот трюк - классический случай умения.

Ответ 5

В стандарте С++ говорится об signed to unsigned преобразованиях ([conv.integral]/2):

Если тип назначения не указан, результирующее значение представляет собой наименьшее целое без знака, сравнимое с исходным целым числом (по модулю 2 n где n - количество бит, используемых для представления неподписанного типа). [Примечание: в представлении с двумя дополнениями это преобразование является концептуальным и нет изменений в битовой схеме (если нет усечения). - конечная нота]

Итак, преобразование -1 в n-разрядное целое без знака всегда даст вам 2 n -1, независимо от того, какая подпись целочисленный тип -1 начался как.

Является ли unsigned x = -1; более или менее читаемым, чем unsigned x = UINT_MAX;, хотя это еще одно обсуждение (определенно есть вероятность, что он поднимет некоторые брови, может быть, даже ваши собственные, когда вы посмотрите на свой собственный код позже;).