¿Se garantiza que un valor de char establecido en CHAR_MAX se ajuste a CHAR_MIN?

10

Mi código:

#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);
}

Salida:

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

Vemos que cuando incrementamos un charconjunto de variables en CHAR_MAX, se ajusta a CHAR_MIN. ¿Está garantizado este comportamiento? ¿O va a ser un comportamiento indefinido o un comportamiento específico de implementación? ¿Qué dice el estándar C99 sobre esto?

[Nota: ¿Qué sucede cuando se da un valor mayor que CHAR_MAX (127) a char o C- por qué char c = 129 se convertirá en -127? no aborda esta pregunta porque hablan de asignar un valor fuera de rango y no incrementar un valor a un valor fuera de rango.]

Aprendiz solitario
fuente
Un incremento es una tarea.
William Pursell
2
Depende de si el personaje está firmado o no. El desbordamiento de enteros con signo es un comportamiento indefinido. Entonces la salida puede ser cualquier cosa.
DaBler

Respuestas:

15

La pregunta es doble: en primer lugar, es

char c = CHAR_MAX;
c += 1;

evaluado de manera diferente de

char c = CHAR_MAX;
c = c + 1;

y la respuesta es no, no lo es , porque C11 / C18 6.5.16.2p3 :

  1. Una asignación compuesta de la forma E1 op = E2es equivalente a la expresión de asignación simple, E1 = E1 op (E2)excepto que el valor l E1se evalúa solo una vez, y con respecto a una llamada de función secuenciada indeterminadamente, la operación de una asignación compuesta es una evaluación única. Si E1tiene un tipo atómico, la asignación compuesta es una operación de lectura-modificación-escritura con memory_order_seq_cstsemántica de orden de memoria. 113)

Entonces, la pregunta es qué sucede en c = c + 1. Aquí los operandos se +someten a las conversiones aritméticas habituales cy 1, por lo tanto, son promovidos a int, a menos que una arquitectura realmente loca requiera que charse promueva unsigned int. +Luego se evalúa el cálculo de , y el resultado, de tipo int/ unsigned intse vuelve a convertir chary se almacena en c.

Hay 3 formas definidas por la implementación en las que esto puede evaluarse:

  • CHAR_MINes 0 y, por charlo tanto, no está firmado.

    Cualquiera de los dos chares promovido intao unsigned inty si se promociona a un int, entonces CHAR_MAX + 1necesariamente encajará en un inttambién, y no se desbordará, o si unsigned intpuede encajar o ajustarse a cero. Cuando el valor resultante, que es numéricamente CHAR_MAX + 1o 0después de la reducción del módulo, vuelva a c, después de la reducción del módulo, se convertirá en 0, es decirCHAR_MIN

  • De charlo contrario, se firma, entonces si CHAR_MAX es menor que INT_MAX, el resultado de CHAR_MAX + 1se ajustará a int, y el estándar C11 / C18 6.3.1.3p3 se aplica a la conversión que ocurre después de la asignación :

    1. De lo contrario, el nuevo tipo se firma y el valor no se puede representar en él; el resultado está definido por la implementación o se genera una señal definida por la implementación.
  • O, si f sizeof (int) == 1 y char está firmado, entonces charse promociona a an int, y CHAR_MAX == INT_MAX=> CHAR_MAX + 1causará un desbordamiento de enteros y el comportamiento será indefinido .

Es decir, los posibles resultados son:

  • Si chares un tipo entero sin signo, el resultado es siempre 0, es decir CHAR_MIN.

  • De charlo contrario, es un tipo entero con signo, y el comportamiento está definido por la implementación / indefinido:

    • CHAR_MIN o algún otro valor definido por la implementación,
    • se genera una señal definida por la implementación, posiblemente terminando el programa,
    • o el comportamiento no está definido en algunas plataformas donde sizeof (char) == sizeof (int).

Todas las operaciones de incremento c = c + 1, c += 1, c++y ++ctienen los mismos efectos secundarios en la misma plataforma. El valor evaluado de la expresión c++será el valor canterior al incremento; para los otros tres, será el valor de cdespués del incremento.

Antti Haapala
fuente
1
sizeof(int) == 1requeriría CHAR_BITS >= 16, ¿verdad?
sepp2k
3
@ sepp2k <pedantic>IDK sobre CHAR_BITSpero lo CHAR_BITharía >= 16</pedantic>.
Antti Haapala
2
Una razón más por la que charsiempre debe estar sin firmar por defecto.
chqrlie
1
@chqrlie Estoy de acuerdo, desafortunadamente podría ser solo que fue firmado por defecto porque no firmado fue más adelante en la historia, podría ser demasiado difícil de cambiar ahora en algunos sistemas cr * ppy debido a la gran cantidad de programas rotos que esperan que EOF encaje en un char ..
Antti Haapala
1
A veces también es claro agregar una respuesta directa: "¿Se garantiza que un valor de char establecido en CHAR_MAX se ajuste a CHAR_MIN?" -> No.
chux - Restablece Monica