Perché succede questo con l’operatore sizeof quando si confronta con un numero negativo?

Cosa sta succedendo davvero qui? L’output ora è “False”:

#include  int main() { if (sizeof(int) > any_negative_integer) printf("True"); else printf("False"); return 0; } 

Se lo cambio a:

 if (sizeof(int) < any_negative_integer) 

l’output è “True”.

Aggiornamento: la stessa domanda è già stata posta, non ho potuto trovarla prima di chiedere.

sizeof restituisce size_t che è senza segno e quindi -1 viene convertito in un numero senza segno molto grande. Usare il giusto livello di avvertimento avrebbe aiutato qui, -Wconversion con la -Wconversion o -Weverything (si noti che non è per uso in produzione ) ci avverte:

 warning: implicit conversion changes signedness: 'int' to 'unsigned long' [-Wsign-conversion] if (sizeof(int) > -1) ~ ^~ 

Per gcc si riceve un avviso simile usando la flag -Wextra :

 warning: comparison between signed and unsigned integer expressions [-Wsign-compare] if (sizeof(int) > -1) ^ 

Per riferimento, sappiamo che size_t non è firmato dalla bozza di standard C99 sezione 7.17 Definizioni comuni che dice:

  size_t 

che è il tipo intero senza segno del risultato dell’operatore sizeof; […]

Nota, non specifica nient’altro sul tipo, nel mio caso specifico capita di essere non firmato a lungo ma non deve essere.

La conversione di -1 è dovuta alla normale conversione aritmetica descritta nella sezione 6.3.1.8 Conversioni aritmetiche usuali che dice:

[…]

Altrimenti, se l’operando che ha un numero intero senza segno ha rank superiore o uguale al rank del tipo di un altro operando, allora l’operando con tipo intero con segno viene convertito nel tipo dell’operando con tipo intero senza segno.

Altrimenti, se il tipo dell’operando con tipo intero con segno può rappresentare tutti i valori del tipo dell’operando con tipo intero senza segno, allora l’operando con tipo intero senza segno viene convertito nel tipo dell’operando con tipo intero con segno.

In caso contrario, entrambi gli operandi vengono convertiti nel tipo intero senza segno corrispondente al tipo di operando con tipo intero con segno.

Quindi l’unica volta che -1 non verrebbe convertito in un valore senza segno sarebbe se int potesse rappresentare tutti i valori di size_t , il che non è il caso qui.

Perché -1 finisce per essere un grande valore senza segno, in realtà finisce per essere il valore massimo del tipo non firmato è dovuto alla sezione 6.3.1.3 interi firmati e non firmati che dice:

Altrimenti, se il nuovo tipo non è firmato, il valore viene convertito aggiungendo o sottraendo ripetutamente un valore superiore al valore massimo che può essere rappresentato nel nuovo tipo finché il valore non si trova nell’intervallo del nuovo tipo. 49)

Quindi finiamo con:

 -1 + (UMAX + 1) 

che è:

 UMAX 

e così finiscono con:

 if (sizeof(int) > UMAX ) 

Perché sizeof() restituisce un size_t , un tipo senza segno. Il confronto tra i tipi con segno e senza segno può dare risultati sorprendenti a causa del cast implicito prima del confronto.