Значение char, установленное в CHAR_MAX, гарантированно обернуто в CHAR_MIN? - PullRequest
10 голосов
/ 08 марта 2020

Мой код:

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

int main()
{
    char c = CHAR_MAX;
    c += 1;
    printf("CHAR_MIN=%d CHAR_MAX=%d c=%d (%c)\n", CHAR_MIN, CHAR_MAX, c, c);
}

Вывод:

CHAR_MIN=-128 CHAR_MAX=127 c=-128 ()

Мы видим, что когда мы увеличиваем переменную char, установленную на CHAR_MAX, она оборачивается до CHAR_MIN , Это поведение гарантировано? Или это будет неопределенное поведение или поведение, определяемое реализацией? Что стандарт C99 говорит об этом?

[Примечание: Что происходит, когда присваивает значение, большее, чем CHAR_MAX (127), для char или C - почему char c = 129 будет преобразован в -127? не решает этот вопрос, потому что они говорят о назначении значения вне диапазона, не увеличивая значение до значения вне диапазона.]

1 Ответ

15 голосов
/ 08 марта 2020

Вопрос двоякий: во-первых,

char c = CHAR_MAX;
c += 1;

оценивается иначе, чем

char c = CHAR_MAX;
c = c + 1;

, и ответом является нет, это не , потому что C11 / C18 6.5.16.2p3 :

Составное присвоение формы E1 op = E2 эквивалентно выражению простого присваивания E1 = E1 op (E2), за исключением того, что значение l 1016 * вычисляется только один раз, и в отношении вызова функции с неопределенной последовательностью - операция составного Задание является единственной оценкой. Если E1 имеет тип atomi c, составное присваивание является операцией чтения-изменения-записи с memory_order_seq_cst семантикой порядка памяти. 113)

Тогда возникает вопрос, что происходит в c = c + 1. Здесь операнды к + при go обычных арифметических c преобразованиях и c и 1, следовательно, повышаются до int, если только в действительно дурацкой архитектуре не требуется, чтобы char повышалось до unsigned int , Затем вычисляется вычисление +, и результат типа int / unsigned int преобразуется обратно в char и сохраняется в c.

. Имеется 3 определяемые реализацией способы, которыми это затем может быть оценено:

  • CHAR_MIN равно 0 и, следовательно, char не подписано.

    Либо char затем повышается до int или unsigned int, и если оно повышается до int, то CHAR_MAX + 1 обязательно будет также соответствовать int и не будет переполнено или, если unsigned int, он может соответствовать или обнуляться. Когда полученное значение, которое численно равно или CHAR_MAX + 1 или 0 после уменьшения по модулю, возвращается к c, после уменьшения по модулю оно становится равным 0, то есть CHAR_MIN

  • В противном случае char подписывается, тогда, если CHAR_MAX меньше INT_MAX, результат CHAR_MAX + 1 будет соответствовать int, и стандарт C11 / C18 6.3.1.3p3 применяется к преобразование, которое происходит при назначении :

    В противном случае новый тип подписывается и значение не может быть представлено в нем; либо результат определяется реализацией, либо определяется определяемый реализацией сигнал.
  • Или iff sizeof (int) == 1 и char подписывается, затем char повышается до int, а CHAR_MAX == INT_MAX => CHAR_MAX + 1 вызовет целочисленное переполнение, и поведение будет неопределенным .

Т.е. возможны следующие результаты:

  • Если char - целочисленный тип без знака, результат всегда 0, т.е. CHAR_MIN .

  • В противном случае char является целочисленным типом со знаком, а поведение определяется реализацией / не определено:

    • CHAR_MIN или какой-либо другой реализацией- определенное значение,
    • подается определенный для реализации сигнал, возможно, завершающий программу,
    • или поведение не определено на некоторых платформах, где sizeof (char) == sizeof (int).

Все операции приращения c = c + 1, c += 1, c++ и ++c имеют одинаковые побочные эффекты на одной и той же платформе. Оцененное значение выражения c++ будет значением c до приращения; для остальных трех это будет значение c после приращения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...