Значение char, установленное в CHAR_MAX, гарантированно обернуто в CHAR_MIN?

10

Мой код:

#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 или C больше, чем CHAR_MAX (127) , преобразуется в -127 в char ? не рассматривает этот вопрос, потому что они говорят о присвоении значения вне диапазона, не увеличивая значение до значения вне диапазона.]

Одинокий ученик
источник
Приращение является присваиванием.
Уильям Перселл
2
Это зависит от того, является ли символ подписанным или неподписанным. Переполнение целых чисел со знаком - неопределенное поведение. Поэтому на выходе может быть что угодно.
Даблер

Ответы:

15

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

char c = CHAR_MAX;
c += 1;

оценивается по-другому от

char c = CHAR_MAX;
c = c + 1;

и ответ нет, это не так , потому что C11 / C18 6.5.16.2p3 :

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

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

Есть 3 способа реализации, в которых это можно оценить:

  • CHAR_MIN0 и, следовательно 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 применяется к преобразованию, которое происходит после присвоения :

    1. В противном случае новый тип подписывается, и значение не может быть представлено в нем; либо результат определяется реализацией, либо определяется сигнал реализации.
  • Или, если 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после приращения.

Антти Хаапала
источник
1
sizeof(int) == 1потребуется CHAR_BITS >= 16, верно?
sepp2k
3
@ sepp2k <pedantic>ИДК о, CHAR_BITSно CHAR_BITбудет >= 16</pedantic>.
Антти Хаапала
2
Еще одна причина, почему charвсегда должен быть без знака по умолчанию.
Chqrlie
1
@chqrlie Я согласен, к сожалению, это может быть просто потому, что он был подписан по умолчанию, потому что unsigned был позже в истории, его может быть слишком сложно изменить сейчас на некоторых системах cr * ppy из-за огромного количества сломанных программ, ожидающих, что EOF поместится в символ ..
Антти Хаапала
1
Иногда также ясно добавить прямой ответ: «Гарантируется ли значение char, установленное в CHAR_MAX, обернуть в CHAR_MIN?» -> Нет.
chux - Восстановить Монику