lungo lungo in C / C ++


84

Sto provando questo codice sul compilatore C ++ di GNU e non sono in grado di comprenderne il 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;
}

Quando rimuovo il commento dalla riga commentata, il codice non viene compilato e restituisce un errore:

errore: la costante intera è troppo grande per il tipo lungo

Tuttavia, se il codice viene compilato così com'è e viene eseguito, produce valori molto maggiori di 10000000000.

Perché?


8
Potrebbe essere troppo tardi ora, ma per i futuri lettori, suggerisco di usare <stdint.h>e utilizzare uint64_t. Per visualizzare un valore a 64 bit,printf( "%" PRIu64 "\n", val);
entusiastico il

@enthusiasticgeek <stdint.h>included,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 1Vedi stackoverflow.com/questions/14535556/…
entusiasticgeek

Risposte:


148

Le lettere 100000000000 costituiscono una costante intera letterale, ma il valore è troppo grande per il tipo int. È necessario utilizzare un suffisso per modificare il tipo di letterale, ad es

long long num3 = 100000000000LL;

Il suffisso LLtrasforma il letterale in tipo long long. C non è abbastanza "intelligente" per concludere questo dal tipo a sinistra, il tipo è una proprietà del letterale stesso, non del contesto in cui viene utilizzato.


47
Ai tempi in cui questa risposta è stata scritta probabilmente era corretto, ma ora lo standard C ++ dice che il tipo di un letterale intero con nessun suffisso è il primo di int, long inte long long intin cui può essere rappresentato il suo valore. [C ++ §2.14.2 / 2] Quindi ora non c'è bisogno di aggiungere il suffisso 'LL' a un intero letterale troppo grande per altri tipi.
bames53

8
Il motivo per cui questo era un problema prima non era perché C ++ non era abbastanza `` intelligente '' per determinare il tipo letterale dal tipo di variabile a cui veniva assegnato, sarebbe stato semplicemente perché l'estensione del compilatore non implementava l'intero esteso tipo in modo che funzioni bene con la lingua standard. C ++ ora ha regole tali che qualsiasi tipo intero esteso si integrerà meglio con lo standard: open-std.org/jtc1/sc22/wg21/docs/papers/2006/n1988.pdf
bames53

4
@unwind Penso che la risposta dovrebbe essere modificata in base a questi suggerimenti.
Antonio

26

Provare:

num3 = 100000000000LL;

E BTW, in C ++ questa è un'estensione del compilatore, lo standard non definisce long long, questo fa parte di C99.


11
Bene, C ++ 11 ora definisce long long
Mohamed El-Nakib

4

Dipende dalla modalità di compilazione. long long non fa parte dello standard C ++ ma solo (di solito) supportato come estensione. Ciò influisce sul tipo di letterali. I letterali interi decimali senza suffisso sono sempre di tipo int se int è abbastanza grande da rappresentare il numero, altrimenti long. Se il numero è anche troppo grande per un lungo periodo, il risultato è definito dall'implementazione (probabilmente solo un numero di tipo long int che è stato troncato per compatibilità con le versioni precedenti). In questo caso devi usare esplicitamente il suffisso LL per abilitare l'estensione long long (sulla maggior parte dei compilatori).

La prossima versione C ++ supporterà ufficialmente long long in un modo che non avrai bisogno di alcun suffisso a meno che tu non voglia esplicitamente che la forza del tipo letterale sia almeno long long. Se il numero non può essere rappresentato in long, il compilatore proverà automaticamente a utilizzare long long anche senza il suffisso LL. Credo che questo sia anche il comportamento di C99.


1

il tuo codice si compila bene qui (anche con quella riga non commentata. ho dovuto cambiarlo in

num3 = 100000000000000000000;

per iniziare a ricevere l'avviso.


Quale compilatore? In C ++, un intero letterale è il più piccolo tra int o long in cui si adatta. In C99, è il più piccolo tra int, long, long long. Quindi, quando ci si imbatte a lungo in C ++ come estensione non standard, forse il compilatore ha adottato anche le regole C99 per i letterali.
Steve Jessop,

gcc versione 4.3.2 (Debian 4.3.2-1.1) su un sistema Linux a 64 bit.
Omry Yadan,

@SteveJessop Un po 'in ritardo forse: ma lungo NON è necessariamente 64 bit. Il più delle volte lo è, ma non hai garanzie che sia ovunque. L'unica garanzia che hai è che sia grande almeno quanto un int, che a sua volta è grande almeno quanto un int breve, che a sua volta è grande almeno quanto un carattere. Infine, char è definito come abbastanza grande da rappresentare ogni carattere nel set di caratteri di base dell'implementazione (tipicamente 8 bit).
pauluss86

@ pauluss86: non stavo parlando di garanzie. Omry ha detto che stava usando gcc 4.3.2 su un sistema Debian a 64 bit. Ho osservato che questo spiegava ciò che stava vedendo poiché (mi è capitato di sapere per una questione di conoscenza generale) gcc è configurato di default su tali sistemi per utilizzare un 64 bit longin linea con l'ABI LP64 di quel sistema operativo.
Steve Jessop

@SteveJessop non sto suggerendo che il tuo commento sia sbagliato! Solo sottolineando che l'ipotesi che un lungo sia sempre 64 bit ovunque, cosa che purtroppo molte persone pensano, è pericolosa.
pauluss86
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.