Un valore char impostato su CHAR_MAX è garantito per essere impostato su CHAR_MIN?


10

Il mio codice:

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

Produzione:

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

Vediamo che quando incrementiamo una charvariabile impostata su CHAR_MAX, si avvolge intorno a CHAR_MIN. Questo comportamento è garantito? O sarà un comportamento indefinito o un comportamento specificato dall'implementazione? Cosa dice lo standard C99 al riguardo?

[Nota: cosa succede quando dai un valore maggiore di CHAR_MAX (127) a char o C- perché char c = 129 verrà convertito in -127? non affronta questa domanda perché parlano dell'assegnazione di un valore fuori range e non dell'incremento di un valore su un valore fuori range.]


Un incremento è un compito.
William Pursell

2
Dipende se il carattere è firmato o non firmato. L'overflow di numeri interi con segno è un comportamento indefinito. Quindi l'output può essere qualsiasi cosa.
DaBler

Risposte:


15

La domanda è duplice: in primo luogo lo è

char c = CHAR_MAX;
c += 1;

valutato diversamente da

char c = CHAR_MAX;
c = c + 1;

e la risposta è no non lo è , perché C11 / C18 6.5.16.2p3 :

  1. Un'assegnazione composta del modulo E1 op = E2equivale all'espressione di assegnazione semplice, E1 = E1 op (E2)tranne per il fatto che il valore E1viene valutato una sola volta, e rispetto a una chiamata di funzione in sequenza indeterminata, l'operazione di un'assegnazione composta è una valutazione singola. Se E1ha un tipo atomico, l'assegnazione composta è un'operazione di lettura-modifica-scrittura con memory_order_seq_cstsemantica dell'ordine di memoria. 113)

Quindi, la domanda è: cosa succede dentro c = c + 1. Qui gli operandi sono +sottoposti alle solite conversioni aritmetiche ce 1sono quindi promossi int, a meno che non charsia promossa un'architettura davvero stravagante unsigned int. Il calcolo di +viene quindi valutato e il risultato di tipo int/ unsigned intviene riconvertito chare archiviato c.

Esistono 3 modi definiti dall'implementazione in cui questo può essere valutato:

  • CHAR_MINè 0 e quindi charnon è firmato.

    O charviene quindi promosso a into unsigned inte se viene promosso a un int, quindi CHAR_MAX + 1si adatta necessariamente anche a un inte non trabocca, o se unsigned intpuò adattarsi o spostarsi a zero. Quando il valore risultante, che è numericamente CHAR_MAX + 1o 0dopo la riduzione del modulo, torna a c, dopo la riduzione del modulo, diventerà 0, cioèCHAR_MIN

  • Altrimenti charviene firmato, quindi se CHAR_MAX è minore di INT_MAX, il risultato di CHAR_MAX + 1si adatta a un int, e lo standard C11 / C18 6.3.1.3p3 si applica alla conversione che avviene al momento dell'assegnazione :

    1. Altrimenti, il nuovo tipo è firmato e il valore non può essere rappresentato in esso; il risultato è definito dall'implementazione o viene generato un segnale definito dall'implementazione.
  • Oppure, iff sizeof (int) == 1 e char viene firmato, quindi charviene promosso a an inte CHAR_MAX == INT_MAX=> CHAR_MAX + 1causerà un overflow di numeri interi e il comportamento sarà indefinito .

Vale a dire i possibili risultati sono:

  • Se charè un tipo intero senza segno, il risultato è sempre 0, ovvero CHAR_MIN.

  • Altrimenti charè un tipo intero con segno e il comportamento è definito / non definito dall'implementazione:

    • CHAR_MIN o qualche altro valore definito dall'implementazione,
    • viene emesso un segnale definito dall'implementazione, eventualmente terminando il programma,
    • o il comportamento non è definito su alcune piattaforme in cui sizeof (char) == sizeof (int).

Tutte le operazioni di incremento c = c + 1, c += 1, c++e ++channo gli stessi effetti collaterali sulla stessa piattaforma. Il valore valutato dell'espressione c++sarà il valore di cprima dell'incremento; per gli altri tre, sarà il valore di cdopo l'incremento.


1
sizeof(int) == 1richiederebbe CHAR_BITS >= 16, giusto?
sepp2k

3
@ sepp2k <pedantic>IDK circa CHAR_BITSma CHAR_BITsarebbe >= 16</pedantic>.
Antti Haapala

2
Un motivo in più per cui chardovrebbe sempre essere non firmato per impostazione predefinita.
Chqrlie

1
@chqrlie Sono d'accordo, sfortunatamente potrebbe essere solo che sia stato firmato per impostazione predefinita perché unsigned era più avanti nella storia, potrebbe essere troppo difficile cambiare ora su alcuni sistemi cr * ppy a causa della mera quantità di programmi rotti che si aspettano che EOF si inserisse in un char ..
Antti Haapala

1
A volte è chiaro anche aggiungere una risposta diretta: "Un valore di carattere impostato su CHAR_MAX è garantito per essere impostato su CHAR_MIN?" -> No.
chux - Ripristina Monica il
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.