¿cuál es el motivo para declarar explícitamente L o UL para valores largos?

De un ejemplo

unsigned long x = 12345678UL 

Siempre hemos aprendido que el comstackdor necesita ver solo “largo” en el ejemplo anterior para configurar 4 bytes (en 32 bits) de memoria. La pregunta es por qué deberíamos usar L / UL en constantes largas incluso después de declarar que es larga.

Cuando no se usa un sufijo L o UL , el comstackdor utiliza el primer tipo que puede contener la constante de una lista (consulte los detalles en el estándar C99, cláusula 6.4.4: 5. Para una constante decimal, la lista es int , long int , long long int ).

Como consecuencia, la mayoría de las veces, no es necesario usar el sufijo. No cambia el significado del progtwig. No cambia el significado de la inicialización de ejemplo de x para la mayoría de las architectures, aunque lo haría si hubiera elegido un número que no podría representarse como de long long . Ver también la respuesta de codebauer para un ejemplo donde la parte U del sufijo es necesaria.


Hay un par de circunstancias en que el progtwigdor puede querer establecer el tipo de la constante explícitamente. Un ejemplo es cuando se usa una función variadica:

 printf("%lld", 1LL); // correct printf("%lld", 1); // undefined behavior 

Una razón común para usar un sufijo es garantizar que el resultado de un cálculo no se desborde. Dos ejemplos son:

 long x = 10000L * 4096L; unsigned long long y = 1ULL << 36; 

En ambos ejemplos, sin sufijos, las constantes tendrían tipo int y el cálculo se haría como int . En cada ejemplo, esto implica un riesgo de desbordamiento. Usar los sufijos significa que el cálculo se realizará en un tipo más grande, que tiene un rango suficiente para el resultado.

Como dice Lightness Races en Orbit, el sufijo litteral viene antes de la asignación. En los dos ejemplos anteriores, simplemente declarar x como long y y como unsigned long long no es suficiente para evitar el desbordamiento en el cálculo de las expresiones que se les asignan.


Otro ejemplo es la comparación x < 12U donde la variable x tiene tipo int . Sin el sufijo U , el comstackdor escribe la constante 12 como int , y la comparación es, por lo tanto, una comparación de las entradas firmadas.

 int x = -3; printf("%d\n", x < 12); // prints 1 because it's true that -3 < 12 

Con el sufijo U , la comparación se convierte en una comparación de enteros sin signo. "Conversiones aritméticas habituales" significa que -3 se convierte en una gran int sin signo:

 printf("%d\n", x < 12U); // prints 0 because (unsigned int)-3 is large 

De hecho, el tipo de una constante puede incluso cambiar el resultado de un cálculo aritmético, de nuevo debido a la forma en que funcionan las "conversiones aritméticas habituales".


Tenga en cuenta que, para las constantes decimales, la lista de tipos sugerida por C99 no contiene unsigned long long . En C90, la lista finalizaba con el tipo entero sin signo estandarizado más grande en ese momento (que unsigned long tenía unsigned long ). Una consecuencia fue que el significado de algunos progtwigs se modificó al agregar el tipo estándar long long a C99: la misma constante que se tipeó como unsigned long en C90 ahora podría escribirse como una long long firmada. Creo que esta es la razón por la cual en C99, se decidió no haber unsigned long long en la lista de tipos de constantes decimales. Vea esto y este blog para un ejemplo.

Porque los literales numéricos son típicamente de tipo int. El UL / L le dice al comstackdor que no son de tipo int, por ejemplo, suponiendo 32bit int y 64bit long

 long i = 0xffff; long j = 0xffffUL; 

Aquí los valores de la derecha se deben convertir a largos firmados (32 bits -> 64 bits)

  1. El “0xffff”, un int, se convertiría a una larga extensión de signo de uso, lo que daría como resultado un valor negativo (0xffffffff)
  2. El “0xffffUL”, un largo sin signo, se convertiría en un valor largo, lo que generaría un valor positivo (0x0000ffff)

La pregunta es por qué deberíamos usar L / UL en constantes largas incluso después de declarar que es larga.

Porque no es “después”; es “antes”

Primero tienes el literal, luego se convierte a lo que sea que el tipo sea de la variable en la que tratas de exprimirlo.

Relacionado con esta publicación, ¿por qué?

Una razón para u es permitir una constante entera mayor que LLONG_MAX en forma decimal.

 // Likely to generate a warning. unsigned long long limit63bit = 18446744073709551615`; // 2^64 - 1 // OK unsigned long long limit63bit = 18446744073709551615u`;