muito tempo em C / C ++

84

Estou tentando este código no compilador C ++ do GNU e não consigo entender seu comportamento:

#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;
}

Ao remover o comentário da linha comentada, o código não compila e apresenta um erro:

erro: a constante inteira é muito grande para o tipo longo

Mas, se o código for compilado como está e for executado, ele produzirá valores muito maiores do que 10000000000.

Por quê?

sud03r
fonte
8
Pode ser tarde demais, mas para futuros leitores, sugiro que você use <stdint.h>e use uint64_t. Para exibir um valor de 64 bits,printf( "%" PRIu64 "\n", val);
entusiasticgeek
@enthusiasticgeek <stdint.h>incluídos,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 );
Herdsman
#define __STDC_FORMAT_MACROS 1Consulte stackoverflow.com/questions/14535556/…
entusiasticgeek

Respostas:

148

As letras 100000000000 constituem uma constante inteira literal, mas o valor é muito grande para o tipo int. Você precisa usar um sufixo para alterar o tipo do literal, ou seja,

long long num3 = 100000000000LL;

O sufixo LLtransforma o literal em tipo long long. C não é "inteligente" o suficiente para concluir isso a partir do tipo à esquerda, o tipo é uma propriedade do próprio literal, não do contexto no qual está sendo usado.

desanuviar
fonte
47
Voltar quando esta resposta foi escrito foi provavelmente correta, mas agora o padrão C ++ diz que o tipo de um literal inteiro sem sufixo é o primeiro de int, long inte long long intem que o seu valor pode ser representado. [C ++ §2.14.2 / 2] Portanto, agora não há necessidade de adicionar o sufixo 'LL' em um literal inteiro que é muito grande para outros tipos.
bames53
8
A razão pela qual isso era um problema antes não era porque C ++ não era 'inteligente' o suficiente para determinar o tipo literal do tipo da variável sendo atribuída, seria simplesmente porque a extensão do compilador não implementou o inteiro estendido digite de forma que funcione bem com a linguagem padrão. C ++ agora tem regras para que qualquer tipo de número inteiro estendido se integre melhor ao padrão: open-std.org/jtc1/sc22/wg21/docs/papers/2006/n1988.pdf
bames53
4
@unwind Acho que a resposta deve ser editada de acordo com essas sugestões.
Antonio
26

Experimentar:

num3 = 100000000000LL;

E por falar nisso, em C ++ isso é uma extensão do compilador, o padrão não define long long, isso faz parte do C99.

Arkaitz Jimenez
fonte
11
Bem, C ++ 11 agora define muito longo
Mohamed El-Nakib
4

Depende de qual modo você está compilando. long long não faz parte do padrão C ++, mas apenas (normalmente) é suportado como extensão. Isso afeta o tipo de literais. Literais inteiros decimais sem qualquer sufixo são sempre do tipo int se int for grande o suficiente para representar o número, caso contrário, longo. Se o número for muito grande por muito tempo, o resultado será definido pela implementação (provavelmente apenas um número do tipo long int que foi truncado para compatibilidade com versões anteriores). Nesse caso, você deve usar explicitamente o sufixo LL para habilitar a extensão longa longa (na maioria dos compiladores).

A próxima versão do C ++ oficialmente suportará long long de uma maneira que você não precisará de nenhum sufixo, a menos que você queira explicitamente que o tipo do literal seja pelo menos long long. Se o número não puder ser representado por muito tempo, o compilador tentará automaticamente usar long long mesmo sem o sufixo LL. Acredito que esse seja o comportamento do C99 também.

Sellibitze
fonte
1

seu código compila aqui bem (mesmo com essa linha não comentada. teve que alterá-lo para

num3 = 100000000000000000000;

para começar a receber o aviso.

Omry Yadan
fonte
Qual compilador? Em C ++, um literal inteiro é o menor de int ou long em que se ajusta. Em C99, é o menor de int, long, long long. Portanto, ao apostar muito no C ++ como uma extensão não padrão, talvez seu compilador também tenha adotado as regras C99 para literais.
Steve Jessop,
gcc versão 4.3.2 (Debian 4.3.2-1.1) em um sistema Linux de 64 bits.
Omry Yadan,
@SteveJessop Um pouco atrasado talvez: mas longo NÃO é necessariamente 64 bits. Na maioria das vezes é, mas você não tem garantias de que estará em todos os lugares. A única garantia que você tem é que ele é pelo menos tão grande quanto um int, que por sua vez é pelo menos tão grande quanto um int curto, que por sua vez é pelo menos tão grande quanto um char. Finalmente, char é definido como grande o suficiente para representar cada caractere no conjunto de caracteres básico da implementação (normalmente 8 bits).
pauluss86
@ pauluss86: Eu não estava falando sobre garantias. Omry disse que estava usando o gcc 4.3.2 em um sistema Debian de 64 bits. Observei que isso explicava o que ele estava vendo, já que (por uma questão de conhecimento geral) o gcc é configurado por padrão em tais sistemas para usar 64 bits longem linha com a ABI LP64 desse SO.
Steve Jessop
@SteveJessop Não estou sugerindo que seu comentário esteja errado! Apenas apontar que a suposição de que um long é sempre 64 bits em todos os lugares, que infelizmente muitas pessoas pensam, é perigosa.
pauluss86