¿Por qué ocurre esto con el operador sizeof cuando se compara con un número negativo?

¿Qué está pasando realmente aquí? La salida ahora es “False”:

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

Si lo cambio a:

 if (sizeof(int) < any_negative_integer) 

la salida es “Verdadero”.

Actualización: ya se ha hecho la misma pregunta , no pude encontrarla antes de preguntar.

sizeof devuelve size_t que no está firmado y, por lo tanto, -1 se está convirtiendo en un número sin signo muy grande. Utilizar el nivel de advertencia correcto habría sido -Wconversion aquí, -Wconversion con la -Wconversion o -Weverything ( note que esto no es para uso de producción ) las banderas nos advierten:

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

Para gcc , recibe una advertencia similar con el indicador -Wextra :

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

Como referencia, sabemos que size_t no tiene firma del borrador de la sección estándar del C99 7.17 Definiciones comunes que dicen:

  size_t 

que es el tipo entero sin signo del resultado del operador sizeof; […]

Tenga en cuenta que no especifica nada más sobre el tipo, en mi caso específico pasa a ser unsigned long pero no tiene que ser así.

La conversión de -1 se debe a la conversión aritmética usual cubierta en la sección 6.3.1.8 Conversiones aritméticas habituales que dice:

[…]

De lo contrario, si el operando que tiene un tipo entero sin signo tiene un rango mayor o igual al rango del tipo del otro operando, entonces el operando con tipo entero con signo se convierte al tipo del operando con tipo entero sin signo.

De lo contrario, si el tipo del operando con tipo entero con signo puede representar todos los valores del tipo del operando con tipo entero sin signo, entonces el operando con tipo entero sin signo se convierte al tipo del operando con tipo entero con signo.

De lo contrario, ambos operandos se convierten al tipo de entero sin signo correspondiente al tipo de operando con tipo de entero con signo.

Por lo tanto, el único momento en que -1 no se convertiría en un valor sin signo sería si int pudiera representar todos los valores de size_t , que no es el caso aquí.

Por qué -1 termina siendo un gran valor sin signo, en realidad termina siendo el valor máximo del tipo sin firmar debido a la sección 6.3.1.3 y sin signo que dice:

De lo contrario, si el nuevo tipo no está firmado, el valor se convierte al agregar o restar repetidamente uno más que el valor máximo que se puede representar en el nuevo tipo hasta que el valor esté en el rango del nuevo tipo. 49)

Así que terminamos con:

 -1 + (UMAX + 1) 

cual es:

 UMAX 

y así terminar con:

 if (sizeof(int) > UMAX ) 

Porque sizeof() devuelve un size_t , un tipo sin firmar. La comparación de tipos firmados y sin firmar puede dar resultados sorprendentes debido a la conversión implícita antes de la comparación.