long long en C / C ++

84

Estoy probando este código en el compilador C ++ de GNU y no puedo entender su comportamiento:

#include <stdio.h>;

int main()
{
    int  num1 = 1000000000;
    long num2 = 1000000000;
    long long num3;
    //num3 = 100000000000;
    long long num4 = ~0;

    printf("%u %u %u", sizeof(num1), sizeof(num2), sizeof(num3));
    printf("%d %ld %lld %llu", num1, num2, num3, num4);
    return 0;
}

Cuando elimino el comentario de la línea comentada, el código no se compila y da un error:

error: la constante entera es demasiado grande para el tipo largo

Pero, si el código se compila como está y se ejecuta, produce valores mucho mayores que 10000000000.

¿Por qué?

sud03r
fuente
8
Puede que sea demasiado tarde ahora, pero para futuros lectores, les sugiero que lo utilicen <stdint.h>y utilicen uint64_t. Para mostrar un valor de 64 bits,printf( "%" PRIu64 "\n", val);
enthusiasticgeek
@enthusiasticgeek <stdint.h>incluido,uint64_t a = 0xffffffffffffff; printf( "%" PRIu64 "\n",a ); : error: expected ‘)’ before ‘PRIu64’ printf( "%" PRIu64 "\n",a ); :: warning: spurious trailing ‘%’ in format [-Wformat=] printf( "%" PRIu64 "\n",a );
Pastor

Respuestas:

147

Las letras 100000000000 forman una constante entera literal, pero el valor es demasiado grande para el tipo int. Debe usar un sufijo para cambiar el tipo de literal, es decir

long long num3 = 100000000000LL;

El sufijo LLconvierte el literal en tipo long long. C no es lo suficientemente "inteligente" para concluir esto a partir del tipo de la izquierda, el tipo es una propiedad del literal en sí, no del contexto en el que se utiliza.

relajarse
fuente
47
Antes, cuando esta respuesta fue escrito probablemente era correcto, pero ahora el estándar C ++ dice que el tipo de un literal entero, sin sufijo es el primero de int, long inty long long inten el que su valor puede ser representado. [C ++ §2.14.2 / 2] Por lo tanto, ahora no es necesario agregar el sufijo 'LL' en un literal entero que es demasiado grande para otros tipos.
bames53
8
La razón por la que esto era un problema antes no era porque C ++ no fuera lo suficientemente 'inteligente' para determinar el tipo literal del tipo de variable a la que se asigna, simplemente habría sido porque la extensión del compilador no implementó el entero extendido escriba de manera que funcione bien con el lenguaje estándar. C ++ ahora tiene reglas tales que cualquier tipo de entero extendido se integrará mejor con el estándar: open-std.org/jtc1/sc22/wg21/docs/papers/2006/n1988.pdf
bames53
4
@unwind Creo que la respuesta debería editarse de acuerdo con estas sugerencias.
Antonio
26

Tratar:

num3 = 100000000000LL;

Y por cierto, en C ++ esta es una extensión del compilador, el estándar no define long long, eso es parte de C99.

Arkaitz Jiménez
fuente
11
Bueno, C ++ 11 ahora define long long
Mohamed El-Nakib
4

Depende del modo que esté compilando. long long no forma parte del estándar C ++, pero solo (normalmente) se admite como extensión. Esto afecta el tipo de literales. Los literales enteros decimales sin ningún sufijo son siempre de tipo int si int es lo suficientemente grande para representar el número, long de lo contrario. Si el número es incluso demasiado grande durante mucho tiempo, el resultado está definido por la implementación (probablemente solo un número de tipo long int que se ha truncado por compatibilidad con versiones anteriores). En este caso, debe usar explícitamente el sufijo LL para habilitar la extensión long long (en la mayoría de los compiladores).

La próxima versión de C ++ admitirá oficialmente long long de una manera que no necesitará ningún sufijo a menos que desee explícitamente que forzar el tipo de literal sea al menos long long. Si el número no se puede representar en long, el compilador automáticamente intentará utilizar long long incluso sin el sufijo LL. Creo que este también es el comportamiento de C99.

sellibitze
fuente
1

su código se compila aquí bien (incluso con esa línea sin comentar. Tuve que cambiarlo a

num3 = 100000000000000000000;

para empezar a recibir la advertencia.

Omry Yadan
fuente
¿Qué compilador? En C ++, un literal entero es el menor de int o long que encaja. En C99, es el menor de int, long, long long. Entonces, cuando se atornilla durante mucho tiempo a C ++ como una extensión no estándar, tal vez su compilador también haya adoptado las reglas C99 para literales.
Steve Jessop
gcc versión 4.3.2 (Debian 4.3.2-1.1) en un sistema Linux de 64 bits.
Omry Yadan
@SteveJessop Un poco tarde quizás: pero largo NO es necesariamente de 64 bits. La mayoría de las veces lo es, pero no tienes garantías de que estará en todas partes. La única garantía que tiene es que es al menos tan grande como un int, que a su vez es al menos tan grande como un int corto, que a su vez es al menos tan grande como un char. Finalmente, char se define como lo suficientemente grande para representar cada carácter en el juego de caracteres básico de la implementación (típicamente de 8 bits).
pauluss86
@ pauluss86: No estaba hablando de garantías. Omry dijo que estaba usando gcc 4.3.2 en un sistema Debian de 64 bits. Observé que esto explicaba lo que estaba viendo ya que (lo sabía como una cuestión de conocimiento general) gcc está configurado de forma predeterminada en dichos sistemas para usar 64 bits longen línea con la ABI LP64 de ese sistema operativo.
Steve Jessop
@SteveJessop ¡No estoy sugiriendo que tu comentario sea incorrecto! Solo señalando que la suposición de que un long es siempre de 64 bits en todas partes, que desafortunadamente mucha gente piensa, es peligrosa.
pauluss86