Гарантируется ли, что присвоение -1 беззнаковому типу даст максимальное значение?

Я нашел несколько вопросов по этой конкретной теме, но они касались C ++.

Насколько переносимо приведение -1 к беззнаковому типу?

преобразование -1 в беззнаковые типы

Безопасно ли присвоить -1 беззнаковому int, чтобы получить максимальное значение?

И при чтении ответов казалось вероятным или, по крайней мере, не маловероятным, что это одна из тех вещей, в которых C и C ++ отличаются.

Вопрос простой:

Если я объявляю переменную с unsigned char/short/int/long var или использую любые другие беззнаковые типы, такие как фиксированная ширина, минимальная ширина и т. Д., Будет ли тогда гарантировано, что var = -1 установит var на максимальное значение, которое он может удерживать? Гарантированно ли эта программа печатает Да?

#include <stdio.h>
#include <limits.h>

int main(void) {
    unsigned long var = -1;
    printf("%s\n", var == ULONG_MAX ? "Yes" : "No");
}

person klutt    schedule 28.01.2021    source источник
comment
но на самом деле, разве это не дубликат того stackoverflow.com/questions/1667963/? Я предположил, что это не так, потому что вы упомянули об этом, но этот ответ буквально говорит The requirements on unsigned arithmetic guarantee that casting -1 to an unsigned type will produce the largest number possible for the target type, и ответ также следует с This is the same in C and C++.   -  person KamilCuk    schedule 28.01.2021
comment
@KamilCuk Я думаю, что лучше сохранить это, так как он сосредоточен только на C, и ваш ответ очень хороший и прямой со ссылками.   -  person klutt    schedule 28.01.2021
comment
@KamilCuk это даже явно относится к стандарту C99: C99, §6.2.5/9, так что это определенно верно для C.   -  person junix    schedule 28.01.2021
comment
Что ж, теперь у нас есть определенная версия C   -  person Antti Haapala    schedule 28.01.2021
comment
@AnttiHaapala Я думаю, что это хорошо. На этот раз я, кажется, пропустил это, но было много раз, когда я задавался вопросом о C, и я вижу множество вопросов с тегами на обоих языках, где трудно найти ответы для C, существуют ли они вообще.   -  person klutt    schedule 28.01.2021
comment
@KamilCuk Мне лично неудобно голосовать за закрытие вопроса о C как обмана на вопрос о C ++ только потому, что в ответе на вопрос о C ++ упоминается, что это применимо и к C.   -  person Andrew Henle    schedule 28.01.2021


Ответы (2)


Гарантируется ли, что присвоение -1 беззнаковому типу даст максимальное значение?

да.

Гарантированно ли эта программа печатает Да?

да.

Это преобразование из int -1 в unsigned long. -1 не может быть представлен как unsigned long. Из C11 6.3.1.3p2:

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

поэтому мы добавляем один (ULONG_MAX + 1) к -1 и получаем -1 + (ULONG_MAX + 1) = ULONG_MAX, который находится в диапазоне unsigned long.

person KamilCuk    schedule 28.01.2021

Преобразование из -1 (signed int) в большой беззнаковый тип четко определено в соответствии с C17 6.3.1.3.

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

К нему прилагается полезная записка 60)

  1. Правила описывают арифметические действия с математическим значением, а не значением данного типа выражения.

Таким образом, учитывая unsigned long var = -1;, значение становится

  • -1 затем добавляем на единицу больше максимального значения unsigned long
  • Значение -1 + ULONG_MAX+1 = U_LONG_MAX.

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

Кроме того, это не зависит от формата подписи, поскольку следует использовать математическое значение, а не необработанное двоичное. Если бы вы сделали что-то вроде unsigned long var = (signed long)0xFFFFFFFFF;, то это была бы другая история в случае экзотических / вымышленных систем с дополнением до единицы или величиной со знаком.

person Lundin    schedule 28.01.2021
comment
В качестве альтернативы вы можете использовать типы stdint.h, поскольку они гарантированно используют 2-дополнение. uint32_t var = (int32_t)0xFFFFFFFFF; сам по себе хорошо определен, но дисфункциональные экзотические системы не обязательно должны предоставлять int32_t, это необязательный тип. - person Lundin; 28.01.2021