cuál es la razón para declarar explícitamente L o UL para valores largos


De un Ejemplo

unsigned long x = 12345678UL

Siempre hemos aprendido que el compilador necesita ver solo "long" en el ejemplo anterior para establecer 4 bytes (en 32 bits) de memoria. La pregunta es por qué debemos usar L / UL en constantes largas incluso después de declararlo como largo.

 23
Author: Shash, 2012-10-30

4 answers

Cuando no se usa un sufijo L o UL, el compilador usa el primer tipo que puede contener la constante de una lista (ver 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 programa. No cambia el significado de su inicialización de ejemplo de x para la mayoría de las arquitecturas, aunque lo haría si hubiera elegido una número que no pudo representarse como long long. Véase también la respuesta de codebauer para un ejemplo donde la parte U del sufijo es necesaria.


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

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

Una razón común para usar un sufijo es asegurarse de 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 habría tipo int y el cálculo se haría como int. En cada ejemplo esto incurre en un riesgo de desbordamiento. El uso de los sufijos significa que el cálculo se hará en un tipo más grande, que tiene suficiente rango para el resultado.

Como la Ligereza Corre en Órbita lo pone, el sufijo del 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 prevenir la desbordamiento en el cálculo de las expresiones asignadas a ellos.


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

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 int sin signo. "Conversiones aritméticas habituales" significa que -3 se convierte en un gran sin signo int:

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

De hecho, el tipo de 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 terminaba con el mayor tipo entero estandarizado sin signo en ese momento (que era unsigned long). Una consecuencia fue que el significado de algunos programas fue cambiado al agregar el tipo estándar long long a C99: la misma constante que se escribió como unsigned long en C90 ahora se puede escribir como long long firmado en su lugar. Creo que esta es la razón por la que en C99, se decidió no tener unsigned long long en la lista de tipos para constantes decimales. Ver this and this blog posts para un ejemplo.

 50
Author: Pascal Cuoq,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-10-30 13:54:18

Porque los literales numéricos son de typicaly de tipo int. El UL / L le dice al compilador que no son de tipo int, por ejemplo, asumiendo 32bit int y 64bit long

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

Aquí los valores de la derecha deben convertirse en longs con signo (32bit -> 64bit)

  1. El "0xffff", un int, se convierte en un largo usando extensión de signo, dando como resultado un valor negativo (0xffffffff)
  2. El "0xffffUL", un long sin signo, se convertiría en un long, dando como resultado un valor positivo (0x0000ffff)
 8
Author: codebauer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-10-30 08:40:25

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

Porque no es "después"; es "antes".

Primero tienes el literal, luego se convierte a cualquiera que sea el tipo de la variable en la que estás tratando de exprimirla.

 5
Author: Lightness Races in Orbit,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-10-30 12:47:44

Relacionado con este post es por qué un u.

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`;
 0
Author: chux,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-10-26 15:17:00